From 774782c74bf85baccf3d52c4811fd4afb152dfab Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 26 Aug 2024 23:39:38 +0100 Subject: [PATCH 01/36] Extract struct field tags Previously we had structs with different trap labels (because the labels already included the tags, which make structs non-identical), but no way to distinguish them in QL. --- go/extractor/dbscheme/tables.go | 7 +++++++ go/extractor/extractor.go | 1 + go/ql/lib/go.dbscheme | 3 +++ go/ql/lib/semmle/go/Types.qll | 11 ++++++++--- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/go/extractor/dbscheme/tables.go b/go/extractor/dbscheme/tables.go index b51dfabf5ca1..74111f161ef1 100644 --- a/go/extractor/dbscheme/tables.go +++ b/go/extractor/dbscheme/tables.go @@ -1159,6 +1159,13 @@ var ComponentTypesTable = NewTable("component_types", EntityColumn(TypeType, "tp"), ).KeySet("parent", "index") +// ComponentTagsTable is the table associating composite types with their component types' tags +var ComponentTagsTable = NewTable("component_tags", + EntityColumn(CompositeType, "parent"), + IntColumn("index"), + StringColumn("tag"), +).KeySet("parent", "index") + // ArrayLengthTable is the table associating array types with their length (represented as a string // since Go array lengths are 64-bit and hence do not always fit into a QL integer) var ArrayLengthTable = NewTable("array_length", diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 3712b7c93937..5fcff0561e02 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1547,6 +1547,7 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { name = "" } extractComponentType(tw, lbl, i, name, field.Type()) + dbscheme.ComponentTagsTable.Emit(tw, lbl, i, tp.Tag(i)) } case *types.Pointer: kind = dbscheme.PointerType.Index() diff --git a/go/ql/lib/go.dbscheme b/go/ql/lib/go.dbscheme index 60e1b7912d7c..40dfd9635451 100644 --- a/go/ql/lib/go.dbscheme +++ b/go/ql/lib/go.dbscheme @@ -209,6 +209,9 @@ alias_rhs(unique int alias: @typealias ref, int tp: @type ref); #keyset[parent, index] component_types(int parent: @compositetype ref, int index: int ref, string name: string ref, int tp: @type ref); +#keyset[parent, index] +component_tags(int parent: @compositetype ref, int index: int ref, string tag: string ref); + array_length(unique int tp: @arraytype ref, string len: string ref); type_objects(unique int tp: @type ref, int object: @object ref); diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 76522e410e9d..05b71d653485 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -565,14 +565,19 @@ class StructType extends @structtype, CompositeType { ) } + private predicate hasComponentTypeAndTag(int i, string name, Type tp, string tag) { + component_types(this, i, name, tp) and component_tags(this, i, tag) + } + language[monotonicAggregates] override string pp() { result = "struct { " + - concat(int i, string name, Type tp | - component_types(this, i, name, tp) + concat(int i, string name, Type tp, string tag | + component_types(this, i, name, tp) and + component_tags(this, i, tag) | - name + " " + tp.pp(), "; " order by i + name + " " + tp.pp() + " " + tag + "; " order by i ) + " }" } From df13f89346e763d2a08d4a1a9661d813b670b81c Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 26 Aug 2024 23:41:58 +0100 Subject: [PATCH 02/36] Look through aliases in hasOwnField --- go/ql/lib/semmle/go/Types.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 05b71d653485..818ce8f082cf 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -440,9 +440,9 @@ class StructType extends @structtype, CompositeType { then ( isEmbedded = true and ( - name = tp.(NamedType).getName() + name = unalias(tp).(NamedType).getName() or - name = tp.(PointerType).getBaseType().(NamedType).getName() + name = unalias(tp).(PointerType).getBaseType().(NamedType).getName() ) ) else ( isEmbedded = false and From 9409b0b90e2cc72985baf00c5b4b105a8b96835c Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 26 Aug 2024 23:43:15 +0100 Subject: [PATCH 03/36] Expose whether functions are variadic in their pp() output --- go/ql/lib/semmle/go/Types.qll | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 818ce8f082cf..fcf0a5f15e5c 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -920,9 +920,12 @@ class SignatureType extends @signaturetype, CompositeType { language[monotonicAggregates] override string pp() { - result = - "func(" + concat(int i, Type tp | tp = this.getParameterType(i) | tp.pp(), ", " order by i) + - ") " + concat(int i, Type tp | tp = this.getResultType(i) | tp.pp(), ", " order by i) + exists(string suffix | (if this.isVariadic() then suffix = "[variadic]" else suffix = "") | + result = + "func(" + concat(int i, Type tp | tp = this.getParameterType(i) | tp.pp(), ", " order by i) + + ") " + concat(int i, Type tp | tp = this.getResultType(i) | tp.pp(), ", " order by i) + + " " + suffix + ) } override string toString() { result = "signature type" } From ac345462ba06fd2398ac5076a8a64227be7f7dd6 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 26 Aug 2024 23:43:43 +0100 Subject: [PATCH 04/36] Implement deep unaliasing, and use it in interface dispatch resolution --- go/extractor/extractor.go | 130 ++++++++++++++++++++-------------- go/ql/lib/semmle/go/Types.qll | 86 +++++++++++++++++++++- 2 files changed, 163 insertions(+), 53 deletions(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 5fcff0561e02..beb392e67a71 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1510,8 +1510,22 @@ func extractSpec(tw *trap.Writer, spec ast.Spec, parent trap.Label, idx int) { // extractType extracts type information for `tp` and returns its associated label; // types are only extracted once, so the second time `extractType` is invoked it simply returns the label func extractType(tw *trap.Writer, tp types.Type) trap.Label { - lbl, exists := getTypeLabel(tw, tp) + return extractTypeWithFlags(tw, tp, false) +} + +func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases bool) trap.Label { + lbl, exists := getTypeLabelWithFlags(tw, tp, transparentAliases) if !exists { + if !transparentAliases { + // Ensure the (deep) underlying type is also extracted, so that it is + // possible to implement deepUnalias in QL. + // For example, if we had type A = int and type B = string, we would need + // to extract map[string]int so that deepUnalias(map[B]A) has a real member + // of @type to return. + // + // TODO: consider using a newtype to do this instead. + extractTypeWithFlags(tw, tp, true) + } var kind int switch tp := tp.(type) { case *types.Basic: @@ -1523,10 +1537,10 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { case *types.Array: kind = dbscheme.ArrayType.Index() dbscheme.ArrayLengthTable.Emit(tw, lbl, fmt.Sprintf("%d", tp.Len())) - extractElementType(tw, lbl, tp.Elem()) + extractElementType(tw, lbl, tp.Elem(), transparentAliases) case *types.Slice: kind = dbscheme.SliceType.Index() - extractElementType(tw, lbl, tp.Elem()) + extractElementType(tw, lbl, tp.Elem(), transparentAliases) case *types.Struct: kind = dbscheme.StructType.Index() for i := 0; i < tp.NumFields(); i++ { @@ -1546,12 +1560,12 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { if field.Embedded() { name = "" } - extractComponentType(tw, lbl, i, name, field.Type()) + extractComponentType(tw, lbl, i, name, field.Type(), transparentAliases) dbscheme.ComponentTagsTable.Emit(tw, lbl, i, tp.Tag(i)) } case *types.Pointer: kind = dbscheme.PointerType.Index() - extractBaseType(tw, lbl, tp.Elem()) + extractBaseType(tw, lbl, tp.Elem(), transparentAliases) case *types.Interface: kind = dbscheme.InterfaceType.Index() for i := 0; i < tp.NumMethods(); i++ { @@ -1561,19 +1575,19 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { // not dealt with by `extractScopes` extractMethod(tw, meth) - extractComponentType(tw, lbl, i, meth.Name(), meth.Type()) + extractComponentType(tw, lbl, i, meth.Name(), meth.Type(), transparentAliases) } for i := 0; i < tp.NumEmbeddeds(); i++ { component := tp.EmbeddedType(i) if isNonUnionTypeSetLiteral(component) { component = createUnionFromType(component) } - extractComponentType(tw, lbl, -(i + 1), "", component) + extractComponentType(tw, lbl, -(i + 1), "", component, transparentAliases) } case *types.Tuple: kind = dbscheme.TupleType.Index() for i := 0; i < tp.Len(); i++ { - extractComponentType(tw, lbl, i, "", tp.At(i).Type()) + extractComponentType(tw, lbl, i, "", tp.At(i).Type(), transparentAliases) } case *types.Signature: kind = dbscheme.SignatureType.Index() @@ -1581,13 +1595,13 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { if params != nil { for i := 0; i < params.Len(); i++ { param := params.At(i) - extractComponentType(tw, lbl, i+1, "", param.Type()) + extractComponentType(tw, lbl, i+1, "", param.Type(), transparentAliases) } } if results != nil { for i := 0; i < results.Len(); i++ { result := results.At(i) - extractComponentType(tw, lbl, -(i + 1), "", result.Type()) + extractComponentType(tw, lbl, -(i + 1), "", result.Type(), transparentAliases) } } if tp.Variadic() { @@ -1595,17 +1609,17 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { } case *types.Map: kind = dbscheme.MapType.Index() - extractKeyType(tw, lbl, tp.Key()) - extractElementType(tw, lbl, tp.Elem()) + extractKeyType(tw, lbl, tp.Key(), transparentAliases) + extractElementType(tw, lbl, tp.Elem(), transparentAliases) case *types.Chan: kind = dbscheme.ChanTypes[tp.Dir()].Index() - extractElementType(tw, lbl, tp.Elem()) + extractElementType(tw, lbl, tp.Elem(), transparentAliases) case *types.Named: origintp := tp.Origin() kind = dbscheme.NamedType.Index() dbscheme.TypeNameTable.Emit(tw, lbl, origintp.Obj().Name()) underlying := origintp.Underlying() - extractUnderlyingType(tw, lbl, underlying) + extractUnderlyingType(tw, lbl, underlying, transparentAliases) trackInstantiatedStructFields(tw, tp, origintp) extractTypeObject(tw, lbl, origintp.Obj()) @@ -1638,14 +1652,18 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { if term.Tilde() { tildeStr = "~" } - extractComponentType(tw, lbl, i, tildeStr, term.Type()) + extractComponentType(tw, lbl, i, tildeStr, term.Type(), transparentAliases) } case *types.Alias: - kind = dbscheme.TypeAlias.Index() - dbscheme.TypeNameTable.Emit(tw, lbl, tp.Obj().Name()) - dbscheme.AliasRhsTable.Emit(tw, lbl, extractType(tw, tp.Rhs())) + if transparentAliases { + extractTypeWithFlags(tw, tp.Rhs(), true) + } else { + kind = dbscheme.TypeAlias.Index() + dbscheme.TypeNameTable.Emit(tw, lbl, tp.Obj().Name()) + dbscheme.AliasRhsTable.Emit(tw, lbl, extractType(tw, tp.Rhs())) - extractTypeObject(tw, lbl, tp.Obj()) + extractTypeObject(tw, lbl, tp.Obj()) + } default: log.Fatalf("unexpected type %T", tp) } @@ -1665,6 +1683,10 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { // is constructed from their globally unique ID. This prevents cyclic type keys // since type recursion in Go always goes through named types. func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { + return getTypeLabelWithFlags(tw, tp, false) +} + +func getTypeLabelWithFlags(tw *trap.Writer, tp types.Type, transparentAliases bool) (trap.Label, bool) { lbl, exists := tw.Labeler.TypeLabels[tp] if !exists { switch tp := tp.(type) { @@ -1672,16 +1694,16 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { lbl = tw.Labeler.GlobalID(fmt.Sprintf("%d;basictype", tp.Kind())) case *types.Array: len := tp.Len() - elem := extractType(tw, tp.Elem()) + elem := extractTypeWithFlags(tw, tp.Elem(), transparentAliases) lbl = tw.Labeler.GlobalID(fmt.Sprintf("%d,{%s};arraytype", len, elem)) case *types.Slice: - elem := extractType(tw, tp.Elem()) + elem := extractTypeWithFlags(tw, tp.Elem(), transparentAliases) lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s};slicetype", elem)) case *types.Struct: var b strings.Builder for i := 0; i < tp.NumFields(); i++ { field := tp.Field(i) - fieldTypeLbl := extractType(tw, field.Type()) + fieldTypeLbl := extractTypeWithFlags(tw, field.Type(), transparentAliases) if i > 0 { b.WriteString(",") } @@ -1693,13 +1715,13 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { } lbl = tw.Labeler.GlobalID(fmt.Sprintf("%s;structtype", b.String())) case *types.Pointer: - base := extractType(tw, tp.Elem()) + base := extractTypeWithFlags(tw, tp.Elem(), transparentAliases) lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s};pointertype", base)) case *types.Interface: var b strings.Builder for i := 0; i < tp.NumMethods(); i++ { meth := tp.Method(i) - methLbl := extractType(tw, meth.Type()) + methLbl := extractTypeWithFlags(tw, meth.Type(), transparentAliases) if i > 0 { b.WriteString(",") } @@ -1710,7 +1732,7 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { if i > 0 { b.WriteString(",") } - fmt.Fprintf(&b, "{%s}", extractType(tw, tp.EmbeddedType(i))) + fmt.Fprintf(&b, "{%s}", extractTypeWithFlags(tw, tp.EmbeddedType(i), transparentAliases)) } // We note whether the interface is comparable so that we can // distinguish the underlying type of `comparable` from an @@ -1722,7 +1744,7 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { case *types.Tuple: var b strings.Builder for i := 0; i < tp.Len(); i++ { - compLbl := extractType(tw, tp.At(i).Type()) + compLbl := extractTypeWithFlags(tw, tp.At(i).Type(), transparentAliases) if i > 0 { b.WriteString(",") } @@ -1734,7 +1756,7 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { params, results := tp.Params(), tp.Results() if params != nil { for i := 0; i < params.Len(); i++ { - paramLbl := extractType(tw, params.At(i).Type()) + paramLbl := extractTypeWithFlags(tw, params.At(i).Type(), transparentAliases) if i > 0 { b.WriteString(",") } @@ -1744,7 +1766,7 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { b.WriteString(";") if results != nil { for i := 0; i < results.Len(); i++ { - resultLbl := extractType(tw, results.At(i).Type()) + resultLbl := extractTypeWithFlags(tw, results.At(i).Type(), transparentAliases) if i > 0 { b.WriteString(",") } @@ -1756,12 +1778,12 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { } lbl = tw.Labeler.GlobalID(fmt.Sprintf("%s;signaturetype", b.String())) case *types.Map: - key := extractType(tw, tp.Key()) - value := extractType(tw, tp.Elem()) + key := extractTypeWithFlags(tw, tp.Key(), transparentAliases) + value := extractTypeWithFlags(tw, tp.Elem(), transparentAliases) lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s},{%s};maptype", key, value)) case *types.Chan: dir := tp.Dir() - elem := extractType(tw, tp.Elem()) + elem := extractTypeWithFlags(tw, tp.Elem(), transparentAliases) lbl = tw.Labeler.GlobalID(fmt.Sprintf("%v,{%s};chantype", dir, elem)) case *types.Named: origintp := tp.Origin() @@ -1779,7 +1801,7 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { case *types.Union: var b strings.Builder for i := 0; i < tp.Len(); i++ { - compLbl := extractType(tw, tp.Term(i).Type()) + compLbl := extractTypeWithFlags(tw, tp.Term(i).Type(), transparentAliases) if i > 0 { b.WriteString("|") } @@ -1790,18 +1812,22 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { } lbl = tw.Labeler.GlobalID(fmt.Sprintf("%s;typesetliteraltype", b.String())) case *types.Alias: - // Ensure that the definition of the aliased type gets extracted - // (which may be an alias in itself). - extractType(tw, tp.Rhs()) + if transparentAliases { + lbl = extractTypeWithFlags(tw, tp.Rhs(), true) + } else { + // Ensure that the definition of the aliased type gets extracted + // (which may be an alias in itself). + extractType(tw, tp.Rhs()) - entitylbl, exists := tw.Labeler.LookupObjectID(tp.Obj(), lbl) - if entitylbl == trap.InvalidLabel { - panic(fmt.Sprintf("Cannot construct label for alias type %v (underlying object is %v).\n", tp, tp.Obj())) - } - if !exists { - extractObject(tw, tp.Obj(), entitylbl) + entitylbl, exists := tw.Labeler.LookupObjectID(tp.Obj(), lbl) + if entitylbl == trap.InvalidLabel { + panic(fmt.Sprintf("Cannot construct label for alias type %v (underlying object is %v).\n", tp, tp.Obj())) + } + if !exists { + extractObject(tw, tp.Obj(), entitylbl) + } + lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s};aliastype", entitylbl)) } - lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s};aliastype", entitylbl)) default: log.Fatalf("(getTypeLabel) unexpected type %T", tp) } @@ -1824,29 +1850,29 @@ func extractTypeObject(tw *trap.Writer, lbl trap.Label, entity *types.TypeName) } // extractKeyType extracts `key` as the key type of the map type `mp` -func extractKeyType(tw *trap.Writer, mp trap.Label, key types.Type) { - dbscheme.KeyTypeTable.Emit(tw, mp, extractType(tw, key)) +func extractKeyType(tw *trap.Writer, mp trap.Label, key types.Type, transparentAliases bool) { + dbscheme.KeyTypeTable.Emit(tw, mp, extractTypeWithFlags(tw, key, transparentAliases)) } // extractElementType extracts `element` as the element type of the container type `container` -func extractElementType(tw *trap.Writer, container trap.Label, element types.Type) { - dbscheme.ElementTypeTable.Emit(tw, container, extractType(tw, element)) +func extractElementType(tw *trap.Writer, container trap.Label, element types.Type, transparentAliases bool) { + dbscheme.ElementTypeTable.Emit(tw, container, extractTypeWithFlags(tw, element, transparentAliases)) } // extractBaseType extracts `base` as the base type of the pointer type `ptr` -func extractBaseType(tw *trap.Writer, ptr trap.Label, base types.Type) { - dbscheme.BaseTypeTable.Emit(tw, ptr, extractType(tw, base)) +func extractBaseType(tw *trap.Writer, ptr trap.Label, base types.Type, transparentAliases bool) { + dbscheme.BaseTypeTable.Emit(tw, ptr, extractTypeWithFlags(tw, base, transparentAliases)) } // extractUnderlyingType extracts `underlying` as the underlying type of the // named type `named` -func extractUnderlyingType(tw *trap.Writer, named trap.Label, underlying types.Type) { - dbscheme.UnderlyingTypeTable.Emit(tw, named, extractType(tw, underlying)) +func extractUnderlyingType(tw *trap.Writer, named trap.Label, underlying types.Type, transparentAliases bool) { + dbscheme.UnderlyingTypeTable.Emit(tw, named, extractTypeWithFlags(tw, underlying, transparentAliases)) } // extractComponentType extracts `component` as the `idx`th component type of `parent` with name `name` -func extractComponentType(tw *trap.Writer, parent trap.Label, idx int, name string, component types.Type) { - dbscheme.ComponentTypesTable.Emit(tw, parent, idx, name, extractType(tw, component)) +func extractComponentType(tw *trap.Writer, parent trap.Label, idx int, name string, component types.Type, transparentAliases bool) { + dbscheme.ComponentTypesTable.Emit(tw, parent, idx, name, extractTypeWithFlags(tw, component, transparentAliases)) } // extractNumLines extracts lines-of-code and lines-of-comments information for the diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index fcf0a5f15e5c..6bdbd8bb24f8 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -89,7 +89,9 @@ class Type extends @type { hasNoMethods(i) or this.hasMethod(getExampleMethodName(i), _) and - forall(string m, SignatureType t | i.hasMethod(m, t) | this.hasMethod(m, t)) + forall(string m, SignatureType t | interfaceHasMethodWithDeepUnaliasedType(i, m, t) | + hasMethodWithDeepUnaliasedType(this, m, t) + ) ) ) } @@ -133,6 +135,13 @@ class Type extends @type { */ PointerType getPointerType() { result.getBaseType() = this } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + /** * Gets a pretty-printed representation of this type, including its structure where applicable. */ @@ -164,6 +173,21 @@ class Type extends @type { } } +pragma[nomagic] +private predicate hasMethodWithDeepUnaliasedType(Type t, string name, SignatureType unaliasedType) { + exists(SignatureType methodType | + t.hasMethod(name, methodType) and + methodType.getDeepUnaliasedType() = unaliasedType + ) +} + +pragma[nomagic] +private predicate interfaceHasMethodWithDeepUnaliasedType( + InterfaceType i, string name, SignatureType unaliasedType +) { + exists(SignatureType t | i.hasMethod(name, t) and t.getDeepUnaliasedType() = unaliasedType) +} + /** An invalid type. */ class InvalidType extends @invalidtype, Type { override string toString() { result = "invalid type" } @@ -404,6 +428,11 @@ class ArrayType extends @arraytype, CompositeType { override Package getPackage() { result = this.getElementType().getPackage() } + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + override string pp() { result = "[" + this.getLength() + "]" + this.getElementType().pp() } override string toString() { result = "array type" } @@ -416,6 +445,10 @@ class SliceType extends @slicetype, CompositeType { override Package getPackage() { result = this.getElementType().getPackage() } + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + override string pp() { result = "[]" + this.getElementType().pp() } override string toString() { result = "slice type" } @@ -569,6 +602,15 @@ class StructType extends @structtype, CompositeType { component_types(this, i, name, tp) and component_tags(this, i, tag) } + override StructType getDeepUnaliasedType() { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + count(int i | component_types(this, i, _, _)) = count(int i | component_types(result, i, _, _)) and + forall(int i, string name, Type tp, string tag | this.hasComponentTypeAndTag(i, name, tp, tag) | + result.hasComponentTypeAndTag(i, name, tp.getDeepUnaliasedType(), tag) + ) + } + language[monotonicAggregates] override string pp() { result = @@ -617,6 +659,10 @@ class PointerType extends @pointertype, CompositeType { ) } + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + override string pp() { result = "* " + this.getBaseType().pp() } override string toString() { result = "pointer type" } @@ -892,6 +938,13 @@ class TupleType extends @tupletype, CompositeType { /** Gets the `i`th component type of this tuple type. */ Type getComponentType(int i) { component_types(this, i, _, result) } + override TupleType getDeepUnaliasedType() { + count(int i | component_types(this, i, _, _)) = count(int i | component_types(result, i, _, _)) and + forall(Type t, int i | t = this.getComponentType(i) | + result.getComponentType(i) = t.getDeepUnaliasedType() + ) + } + language[monotonicAggregates] override string pp() { result = @@ -918,6 +971,18 @@ class SignatureType extends @signaturetype, CompositeType { /** Holds if this signature type is variadic. */ predicate isVariadic() { variadic(this) } + override SignatureType getDeepUnaliasedType() { + count(int i | component_types(this, i, _, _)) = count(int i | component_types(result, i, _, _)) and + ( + this.isVariadic() and result.isVariadic() + or + not this.isVariadic() and not result.isVariadic() + ) and + forall(int i, Type componentType | component_types(this, i, _, componentType) | + component_types(result, i, _, componentType.getDeepUnaliasedType()) + ) + } + language[monotonicAggregates] override string pp() { exists(string suffix | (if this.isVariadic() then suffix = "[variadic]" else suffix = "") | @@ -939,6 +1004,11 @@ class MapType extends @maptype, CompositeType { /** Gets the value type of this map type. */ Type getValueType() { element_type(this, result) } + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + override string pp() { result = "[" + this.getKeyType().pp() + "]" + this.getValueType().pp() } override string toString() { result = "map type" } @@ -963,6 +1033,10 @@ class SendChanType extends @sendchantype, ChanType { override string pp() { result = "chan<- " + this.getElementType().pp() } override string toString() { result = "send-channel type" } + + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } } /** A channel type that can only receive. */ @@ -972,6 +1046,10 @@ class RecvChanType extends @recvchantype, ChanType { override string pp() { result = "<-chan " + this.getElementType().pp() } override string toString() { result = "receive-channel type" } + + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } } /** A channel type that can both send and receive. */ @@ -983,6 +1061,10 @@ class SendRecvChanType extends @sendrcvchantype, ChanType { override string pp() { result = "chan " + this.getElementType().pp() } override string toString() { result = "send-receive-channel type" } + + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } } /** A named type. */ @@ -1021,6 +1103,8 @@ class AliasType extends @typealias, CompositeType { Type getRhs() { alias_rhs(this, result) } override Type getUnderlyingType() { result = unalias(this).getUnderlyingType() } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } } /** From 02ea4331b56fc61813f5479c3615bcab96d04d0f Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 28 Aug 2024 14:00:34 +0100 Subject: [PATCH 05/36] Transparent aliases: don't look through named types --- go/extractor/extractor.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index beb392e67a71..dbec52209316 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1619,7 +1619,7 @@ func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases boo kind = dbscheme.NamedType.Index() dbscheme.TypeNameTable.Emit(tw, lbl, origintp.Obj().Name()) underlying := origintp.Underlying() - extractUnderlyingType(tw, lbl, underlying, transparentAliases) + extractUnderlyingType(tw, lbl, underlying) trackInstantiatedStructFields(tw, tp, origintp) extractTypeObject(tw, lbl, origintp.Obj()) @@ -1866,8 +1866,8 @@ func extractBaseType(tw *trap.Writer, ptr trap.Label, base types.Type, transpare // extractUnderlyingType extracts `underlying` as the underlying type of the // named type `named` -func extractUnderlyingType(tw *trap.Writer, named trap.Label, underlying types.Type, transparentAliases bool) { - dbscheme.UnderlyingTypeTable.Emit(tw, named, extractTypeWithFlags(tw, underlying, transparentAliases)) +func extractUnderlyingType(tw *trap.Writer, named trap.Label, underlying types.Type) { + dbscheme.UnderlyingTypeTable.Emit(tw, named, extractType(tw, underlying)) } // extractComponentType extracts `component` as the `idx`th component type of `parent` with name `name` From e61bb8d7f51932242ab6660da98773deed8f0ebc Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 28 Aug 2024 14:02:53 +0100 Subject: [PATCH 06/36] Transparent aliases: don't write an invalid type to the @types table on extracting an alias --- go/extractor/extractor.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index dbec52209316..51a771dbcfdd 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1656,7 +1656,9 @@ func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases boo } case *types.Alias: if transparentAliases { - extractTypeWithFlags(tw, tp.Rhs(), true) + // Nothing to do; getTypeLabel will already have looked + // through the alias, extracted and returned its RHS. + return lbl } else { kind = dbscheme.TypeAlias.Index() dbscheme.TypeNameTable.Emit(tw, lbl, tp.Obj().Name()) From a0375728f252d7d535bc0a5c7a8fdbf29b7797a4 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 28 Aug 2024 14:03:24 +0100 Subject: [PATCH 07/36] Distinguish types with and without explicit aliases in the type-label cache --- go/extractor/extractor.go | 5 +++-- go/extractor/trap/labels.go | 15 ++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 51a771dbcfdd..0413a51e0a7f 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1689,7 +1689,8 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { } func getTypeLabelWithFlags(tw *trap.Writer, tp types.Type, transparentAliases bool) (trap.Label, bool) { - lbl, exists := tw.Labeler.TypeLabels[tp] + typeLabelKey := trap.TypeLabelsKey{Type: tp, TransparentAliases: transparentAliases} + lbl, exists := tw.Labeler.TypeLabels[typeLabelKey] if !exists { switch tp := tp.(type) { case *types.Basic: @@ -1833,7 +1834,7 @@ func getTypeLabelWithFlags(tw *trap.Writer, tp types.Type, transparentAliases bo default: log.Fatalf("(getTypeLabel) unexpected type %T", tp) } - tw.Labeler.TypeLabels[tp] = lbl + tw.Labeler.TypeLabels[typeLabelKey] = lbl } return lbl, exists } diff --git a/go/extractor/trap/labels.go b/go/extractor/trap/labels.go index 6052149c183d..d9d82679023d 100644 --- a/go/extractor/trap/labels.go +++ b/go/extractor/trap/labels.go @@ -19,6 +19,11 @@ func (lbl *Label) String() string { return lbl.id } +type TypeLabelsKey struct { + Type types.Type + TransparentAliases bool +} + // Labeler is used to represent labels for a file. It is used to write // associate objects with labels. type Labeler struct { @@ -26,10 +31,10 @@ type Labeler struct { nextid int fileLabel Label - nodeLabels map[interface{}]Label // labels associated with AST nodes - scopeLabels map[*types.Scope]Label // labels associated with scopes - objectLabels map[types.Object]Label // labels associated with objects (that is, declared entities) - TypeLabels map[types.Type]Label // labels associated with types + nodeLabels map[interface{}]Label // labels associated with AST nodes + scopeLabels map[*types.Scope]Label // labels associated with scopes + objectLabels map[types.Object]Label // labels associated with objects (that is, declared entities) + TypeLabels map[TypeLabelsKey]Label // labels associated with types keyLabels map[string]Label } @@ -41,7 +46,7 @@ func newLabeler(tw *Writer) *Labeler { make(map[interface{}]Label), make(map[*types.Scope]Label), make(map[types.Object]Label), - make(map[types.Type]Label), + make(map[TypeLabelsKey]Label), make(map[string]Label), } } From 08c195d890aafcd347dd428b2056b296ad2df629 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 29 Aug 2024 14:23:28 +0100 Subject: [PATCH 08/36] Fix Mongodb additional taint step --- go/ql/lib/semmle/go/frameworks/NoSQL.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/frameworks/NoSQL.qll b/go/ql/lib/semmle/go/frameworks/NoSQL.qll index 36932149628e..3326005c60ac 100644 --- a/go/ql/lib/semmle/go/frameworks/NoSQL.qll +++ b/go/ql/lib/semmle/go/frameworks/NoSQL.qll @@ -40,7 +40,8 @@ module NoSql { // Taint an entry if the `Value` is tainted exists(Write w, DataFlow::Node base, Field f | w.writesField(base, f, pred) | base = succ.(DataFlow::PostUpdateNode).getPreUpdateNode() and - base.getType().hasQualifiedName(package("go.mongodb.org/mongo-driver", "bson/primitive"), "E") and + unalias(base.getType()) + .hasQualifiedName(package("go.mongodb.org/mongo-driver", "bson/primitive"), "E") and f.getName() = "Value" ) } From 7cde3dfb3922d6067c3242c4d11156c3db52cba9 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 29 Aug 2024 17:32:33 +0100 Subject: [PATCH 09/36] Don't repeat parts of extractType that populate tracking tables --- go/extractor/extractor.go | 65 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 0413a51e0a7f..6996260ec098 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1546,15 +1546,20 @@ func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases boo for i := 0; i < tp.NumFields(); i++ { field := tp.Field(i) - // ensure the field is associated with a label - note that - // struct fields do not have a parent scope, so they are not - // dealt with by `extractScopes` - fieldlbl, exists := tw.Labeler.FieldID(field, i, lbl) - if !exists { - extractObject(tw, field, fieldlbl) - } + if !transparentAliases { + // ensure the field is associated with a label - note that + // struct fields do not have a parent scope, so they are not + // dealt with by `extractScopes`. + + // Skip this when extracting a type with transparent aliases; + // this is not the definitive version of the type. + fieldlbl, exists := tw.Labeler.FieldID(field, i, lbl) + if !exists { + extractObject(tw, field, fieldlbl) + } - dbscheme.FieldStructsTable.Emit(tw, fieldlbl, lbl) + dbscheme.FieldStructsTable.Emit(tw, fieldlbl, lbl) + } name := field.Name() if field.Embedded() { @@ -1571,9 +1576,14 @@ func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases boo for i := 0; i < tp.NumMethods(); i++ { meth := tp.Method(i) - // Note that methods do not have a parent scope, so they are - // not dealt with by `extractScopes` - extractMethod(tw, meth) + if !transparentAliases { + // Note that methods do not have a parent scope, so they are + // not dealt with by `extractScopes` + + // Skip this when extracting a type with transparent aliases; + // this is not the definitive version of the type. + extractMethod(tw, meth) + } extractComponentType(tw, lbl, i, meth.Name(), meth.Type(), transparentAliases) } @@ -1620,23 +1630,30 @@ func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases boo dbscheme.TypeNameTable.Emit(tw, lbl, origintp.Obj().Name()) underlying := origintp.Underlying() extractUnderlyingType(tw, lbl, underlying) - trackInstantiatedStructFields(tw, tp, origintp) - extractTypeObject(tw, lbl, origintp.Obj()) + if !transparentAliases { + // The transparent and non-transparent versions of a named typed + // should be equal, so this is probably harmless, but regardless + // don't repeat it to save time. - // ensure all methods have labels - note that methods do not have a - // parent scope, so they are not dealt with by `extractScopes` - for i := 0; i < origintp.NumMethods(); i++ { - meth := origintp.Method(i) + trackInstantiatedStructFields(tw, tp, origintp) - extractMethod(tw, meth) - } + extractTypeObject(tw, lbl, origintp.Obj()) + + // ensure all methods have labels - note that methods do not have a + // parent scope, so they are not dealt with by `extractScopes` + for i := 0; i < origintp.NumMethods(); i++ { + meth := origintp.Method(i) - // associate all methods of underlying interface with this type - if underlyingInterface, ok := underlying.(*types.Interface); ok { - for i := 0; i < underlyingInterface.NumMethods(); i++ { - methlbl := extractMethod(tw, underlyingInterface.Method(i)) - dbscheme.MethodHostsTable.Emit(tw, methlbl, lbl) + extractMethod(tw, meth) + } + + // associate all methods of underlying interface with this type + if underlyingInterface, ok := underlying.(*types.Interface); ok { + for i := 0; i < underlyingInterface.NumMethods(); i++ { + methlbl := extractMethod(tw, underlyingInterface.Method(i)) + dbscheme.MethodHostsTable.Emit(tw, methlbl, lbl) + } } } case *types.TypeParam: From b7fac654ac26fe80b97951c3c4710622ba082f1e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 29 Aug 2024 18:05:47 +0100 Subject: [PATCH 10/36] Fix flow through pointer types related by aliasing --- go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index 2fcbf2d350f2..89796f9e10bb 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -153,7 +153,8 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { or node1 = base and node2.(PostUpdateNode).getPreUpdateNode() = node1.(PointerDereferenceNode).getOperand() and - c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType()) + c = + any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType().getDeepUnaliasedType()) ) or node1 = node2.(AddressOperationNode).getOperand() and @@ -172,7 +173,8 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { */ predicate readStep(Node node1, ContentSet c, Node node2) { node1 = node2.(PointerDereferenceNode).getOperand() and - c = any(DataFlow::PointerContent pc | pc.getPointerType() = node1.getType()) + c = + any(DataFlow::PointerContent pc | pc.getPointerType() = node1.getType().getDeepUnaliasedType()) or exists(FieldReadNode read | node2 = read and From 70820054d3f33ef8b0846168a75906ccef6e1716 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 29 Aug 2024 18:39:17 +0100 Subject: [PATCH 11/36] Fix missed case --- go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index 89796f9e10bb..8120044c9c46 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -158,7 +158,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { ) or node1 = node2.(AddressOperationNode).getOperand() and - c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType()) + c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType().getDeepUnaliasedType()) or FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c, node2.(FlowSummaryNode).getSummaryNode()) From eb1e6b1c147c14b89f4a3924ba6c8c06bbeb4068 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 30 Aug 2024 12:47:43 +0100 Subject: [PATCH 12/36] Improve efficiency of composite-type deep-unalias computation --- go/ql/lib/semmle/go/Types.qll | 62 ++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 6bdbd8bb24f8..4104d98bb8cf 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -602,12 +602,25 @@ class StructType extends @structtype, CompositeType { component_types(this, i, name, tp) and component_tags(this, i, tag) } - override StructType getDeepUnaliasedType() { + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { // Note we must use component_types not hasOwnField here because component_types may specify // interface-in-struct embedding, but hasOwnField does not return such members. - count(int i | component_types(this, i, _, _)) = count(int i | component_types(result, i, _, _)) and - forall(int i, string name, Type tp, string tag | this.hasComponentTypeAndTag(i, name, tp, tag) | - result.hasComponentTypeAndTag(i, name, tp.getDeepUnaliasedType(), tag) + ( + i = 0 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | this.hasComponentTypeAndTag(i, name, tp, tag) | + unaliased.hasComponentTypeAndTag(i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + ( + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents = 0 and result = this + ) ) } @@ -938,10 +951,21 @@ class TupleType extends @tupletype, CompositeType { /** Gets the `i`th component type of this tuple type. */ Type getComponentType(int i) { component_types(this, i, _, result) } + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt.getComponentType(i) = this.getDeepUnaliasedType() and + ( + i = 0 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) + } + override TupleType getDeepUnaliasedType() { - count(int i | component_types(this, i, _, _)) = count(int i | component_types(result, i, _, _)) and - forall(Type t, int i | t = this.getComponentType(i) | - result.getComponentType(i) = t.getDeepUnaliasedType() + exists(int nComponents | nComponents = count(int i | exists(this.getComponentType(i))) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + // I don't think Go allows empty tuples in any context, but this is at least harmless. + nComponents = 0 and result = this ) } @@ -971,15 +995,31 @@ class SignatureType extends @signaturetype, CompositeType { /** Holds if this signature type is variadic. */ predicate isVariadic() { variadic(this) } + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + (i = 0 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + (i = 0 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + override SignatureType getDeepUnaliasedType() { - count(int i | component_types(this, i, _, _)) = count(int i | component_types(result, i, _, _)) and + exists(int nParams | nParams = this.getNumParameter() | + nParams = 0 and result.getNumParameter() = 0 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + exists(int nResults | nResults = this.getNumResult() | + nResults = 0 and result.getNumResult() = 0 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) and ( this.isVariadic() and result.isVariadic() or not this.isVariadic() and not result.isVariadic() - ) and - forall(int i, Type componentType | component_types(this, i, _, componentType) | - component_types(result, i, _, componentType.getDeepUnaliasedType()) ) } From 5e457e1079a78f64e1603311b8fece78cee4dc40 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 30 Aug 2024 23:58:53 +0100 Subject: [PATCH 13/36] Make deep-unalias computation even more efficient using unpack routines --- go/ql/lib/semmle/go/Types.qll | 231 +++++++++++++++++++++++++++++----- 1 file changed, 203 insertions(+), 28 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 4104d98bb8cf..ea8eb8ee5495 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -459,6 +459,92 @@ class ByteSliceType extends SliceType { ByteSliceType() { this.getElementType() instanceof Uint8Type } } +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + /** A struct type. */ class StructType extends @structtype, CompositeType { /** @@ -598,29 +684,36 @@ class StructType extends @structtype, CompositeType { ) } - private predicate hasComponentTypeAndTag(int i, string name, Type tp, string tag) { - component_types(this, i, name, tp) and component_tags(this, i, tag) + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { // Note we must use component_types not hasOwnField here because component_types may specify // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - i = 0 or + i = 5 or this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - exists(string name, Type tp, string tag | this.hasComponentTypeAndTag(i, name, tp, tag) | - unaliased.hasComponentTypeAndTag(i, name, tp.getDeepUnaliasedType(), tag) + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - ( - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents = 0 and result = this - ) + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } @@ -961,11 +1054,14 @@ class TupleType extends @tupletype, CompositeType { } override TupleType getDeepUnaliasedType() { - exists(int nComponents | nComponents = count(int i | exists(this.getComponentType(i))) | + exists(int nComponents | + nComponents = count(int i | exists(this.getComponentType(i))) and + nComponents = count(int i | exists(result.getComponentType(i))) + | this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) or // I don't think Go allows empty tuples in any context, but this is at least harmless. - nComponents = 0 and result = this + nComponents = 0 ) } @@ -978,6 +1074,68 @@ class TupleType extends @tupletype, CompositeType { override string toString() { result = "tuple type" } } +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + /** A signature type. */ class SignatureType extends @signaturetype, CompositeType { /** Gets the `i`th parameter type of this signature type. */ @@ -995,31 +1153,48 @@ class SignatureType extends @signaturetype, CompositeType { /** Holds if this signature type is variadic. */ predicate isVariadic() { variadic(this) } + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - (i = 0 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - (i = 0 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } override SignatureType getDeepUnaliasedType() { - exists(int nParams | nParams = this.getNumParameter() | - nParams = 0 and result.getNumParameter() = 0 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - exists(int nResults | nResults = this.getNumResult() | - nResults = 0 and result.getNumResult() = 0 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) and - ( - this.isVariadic() and result.isVariadic() - or - not this.isVariadic() and not result.isVariadic() + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) and + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) ) } From 57e986a6769c28d1a7798e03e925ed0399d2560a Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sat, 31 Aug 2024 18:25:31 +0100 Subject: [PATCH 14/36] Only extract transparent-alias versions of types when necessary --- go/extractor/extractor.go | 90 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 6996260ec098..a2aced3e9fcb 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1513,17 +1513,96 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { return extractTypeWithFlags(tw, tp, false) } +func containsAliasTypes(tp types.Type) bool { + switch tp := tp.(type) { + case *types.Basic: + return false + case *types.Array: + return containsAliasTypes(tp.Elem()) + case *types.Slice: + return containsAliasTypes(tp.Elem()) + case *types.Struct: + for i := 0; i < tp.NumFields(); i++ { + field := tp.Field(i) + if containsAliasTypes(field.Type()) { + return true + } + } + return false + case *types.Pointer: + return containsAliasTypes(tp.Elem()) + case *types.Interface: + for i := 0; i < tp.NumMethods(); i++ { + meth := tp.Method(i) + if containsAliasTypes(meth.Type()) { + return true + } + } + for i := 0; i < tp.NumEmbeddeds(); i++ { + if containsAliasTypes(tp.EmbeddedType(i)) { + return true + } + } + return false + case *types.Tuple: + for i := 0; i < tp.Len(); i++ { + if containsAliasTypes(tp.At(i).Type()) { + return true + } + } + return false + case *types.Signature: + params, results := tp.Params(), tp.Results() + if params != nil { + for i := 0; i < params.Len(); i++ { + param := params.At(i) + if containsAliasTypes(param.Type()) { + return true + } + } + } + if results != nil { + for i := 0; i < results.Len(); i++ { + result := results.At(i) + if containsAliasTypes(result.Type()) { + return true + } + } + } + return false + case *types.Map: + return containsAliasTypes(tp.Key()) || containsAliasTypes(tp.Elem()) + case *types.Chan: + return containsAliasTypes(tp.Elem()) + case *types.Named: + return false + case *types.TypeParam: + return false + case *types.Union: + for i := 0; i < tp.Len(); i++ { + term := tp.Term(i) + if containsAliasTypes(term.Type()) { + return true + } + } + return false + case *types.Alias: + return true + default: + log.Fatalf("unexpected type %T", tp) + } + return false +} + func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases bool) trap.Label { lbl, exists := getTypeLabelWithFlags(tw, tp, transparentAliases) if !exists { - if !transparentAliases { + if !transparentAliases && containsAliasTypes(tp) { // Ensure the (deep) underlying type is also extracted, so that it is // possible to implement deepUnalias in QL. // For example, if we had type A = int and type B = string, we would need // to extract map[string]int so that deepUnalias(map[B]A) has a real member // of @type to return. - // - // TODO: consider using a newtype to do this instead. extractTypeWithFlags(tw, tp, true) } var kind int @@ -1709,6 +1788,11 @@ func getTypeLabelWithFlags(tw *trap.Writer, tp types.Type, transparentAliases bo typeLabelKey := trap.TypeLabelsKey{Type: tp, TransparentAliases: transparentAliases} lbl, exists := tw.Labeler.TypeLabels[typeLabelKey] if !exists { + if transparentAliases && !containsAliasTypes(tp) { + // No aliases involved, so the label is the same as the non-transparent version + // of the same type. + return getTypeLabelWithFlags(tw, tp, false) + } switch tp := tp.(type) { case *types.Basic: lbl = tw.Labeler.GlobalID(fmt.Sprintf("%d;basictype", tp.Kind())) From ab09340f0b567fd97b1f0cb45850320c8ee25c0e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sun, 1 Sep 2024 17:10:15 +0100 Subject: [PATCH 15/36] Fix struct deepUnaliasedType predicate --- go/ql/lib/semmle/go/Types.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index ea8eb8ee5495..baa665cd3825 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -1190,7 +1190,9 @@ class SignatureType extends @signaturetype, CompositeType { ( nParams <= 5 or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) and + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( nResults <= 3 or this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) From 85ab44469b00ec93b859c02c2fb527f35690894f Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sun, 1 Sep 2024 17:43:17 +0100 Subject: [PATCH 16/36] Implement deep-unalias for interface types --- go/ql/lib/semmle/go/Types.qll | 147 ++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index baa665cd3825..d0fa902266a3 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -888,6 +888,101 @@ class TypeSetLiteralType extends @typesetliteraltype, CompositeType { override string toString() { result = "type set literal type" } } +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + /** An interface type. */ class InterfaceType extends @interfacetype, CompositeType { /** Gets the type of method `name` of this interface type. */ @@ -969,6 +1064,58 @@ class InterfaceType extends @interfacetype, CompositeType { .getAnEmbeddedTypeSetLiteral() } + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + language[monotonicAggregates] override string pp() { exists(string comp, string sep1, string ts, string sep2, string meth | From 5d10e36c8012f0ed79b3630e51515642587be3ff Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sun, 1 Sep 2024 17:54:55 +0100 Subject: [PATCH 17/36] Fix TupleType's getDeepUnaliasedType, and make it efficient --- go/ql/lib/semmle/go/Types.qll | 58 ++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index d0fa902266a3..e05c1f2a2054 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -1186,29 +1186,71 @@ class ComparableType extends NamedType { ComparableType() { this.getName() = "comparable" } } +pragma[nomagic] +private predicate unpackTupleType(TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents) { + nComponents = count(int i | component_types(tt, i, _, _)) and + ( + if nComponents >= 1 + then c0 = MkSomeType(tt.getComponentType(0)) + else c0 = MkNoType() + ) and + ( + if nComponents >= 2 + then c1 = MkSomeType(tt.getComponentType(1)) + else c1 = MkNoType() + ) and + ( + if nComponents >= 3 + then c2 = MkSomeType(tt.getComponentType(2)) + else c2 = MkNoType() + ) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType(TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents) { + exists( + OptType c0a, OptType c1a, OptType c2a + | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + /** A tuple type. */ class TupleType extends @tupletype, CompositeType { /** Gets the `i`th component type of this tuple type. */ Type getComponentType(int i) { component_types(this, i, _, result) } + private TupleType getCandidateDeepUnaliasedType() { + exists( + OptType c0, OptType c1, OptType c2, int nComponents + | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt.getComponentType(i) = this.getDeepUnaliasedType() and + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - i = 0 + i = 3 or this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) ) } override TupleType getDeepUnaliasedType() { - exists(int nComponents | - nComponents = count(int i | exists(this.getComponentType(i))) and - nComponents = count(int i | exists(result.getComponentType(i))) - | + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) or - // I don't think Go allows empty tuples in any context, but this is at least harmless. - nComponents = 0 + nComponents <= 3 ) } From 847e11d4d85895f8355c538107c2cdb77129ce05 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sun, 1 Sep 2024 18:22:31 +0100 Subject: [PATCH 18/36] Amend upgrade and downgrade scripts to look through aliases --- .../aliases.qll | 572 +++++++++++++++++ .../array_length.ql | 577 +++++++++++++++++ .../base_type.ql | 577 +++++++++++++++++ .../component_types.ql | 578 +++++++++++++++++ .../element_type.ql | 578 +++++++++++++++++ .../go.dbscheme | 0 .../key_type.ql | 578 +++++++++++++++++ .../objecttypes.ql | 583 +++++++++++++++++ .../old.dbscheme | 3 + .../type_objects.ql | 587 ++++++++++++++++++ .../type_of.ql | 581 +++++++++++++++++ .../typename.ql | 583 +++++++++++++++++ .../types.ql | 582 +++++++++++++++++ .../underlying_type.ql | 579 +++++++++++++++++ .../update_lib_copies.py | 40 ++ .../upgrade.properties | 18 + .../variadic.ql | 577 +++++++++++++++++ .../objects.ql | 14 - .../type_objects.ql | 18 - .../typename.ql | 14 - .../types.ql | 12 - .../upgrade.properties | 7 - .../component_tags.ql | 7 + .../go.dbscheme | 3 + .../upgrade.properties | 1 + 25 files changed, 7604 insertions(+), 65 deletions(-) create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/aliases.qll create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/array_length.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/base_type.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/component_types.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/element_type.ql rename go/downgrades/{60e1b7912d7c68066b13c776b07c2da5fc13342a => 40dfd9635451090c49d1a4f2be8470005ea4a094}/go.dbscheme (100%) create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/key_type.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/objecttypes.ql rename go/downgrades/{60e1b7912d7c68066b13c776b07c2da5fc13342a => 40dfd9635451090c49d1a4f2be8470005ea4a094}/old.dbscheme (99%) create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_objects.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_of.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/typename.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/types.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/underlying_type.ql create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/update_lib_copies.py create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/upgrade.properties create mode 100644 go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/variadic.ql delete mode 100644 go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/objects.ql delete mode 100644 go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/type_objects.ql delete mode 100644 go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/typename.ql delete mode 100644 go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/types.ql delete mode 100644 go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/upgrade.properties create mode 100644 go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/component_tags.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/aliases.qll b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/aliases.qll new file mode 100644 index 000000000000..33de6e892773 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/aliases.qll @@ -0,0 +1,572 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/array_length.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/array_length.ql new file mode 100644 index 000000000000..3850a63a4657 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/array_length.ql @@ -0,0 +1,577 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + from ArrayType at, string length + where array_length(at, length) + and not containsAliases(at) + select at, length \ No newline at end of file diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/base_type.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/base_type.ql new file mode 100644 index 000000000000..ca548f02a20d --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/base_type.ql @@ -0,0 +1,577 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + from PointerType pt, Type base + where base_type(pt, base) + and not containsAliases(pt) + select pt, base \ No newline at end of file diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/component_types.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/component_types.ql new file mode 100644 index 000000000000..2f0dd0e5bd39 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/component_types.ql @@ -0,0 +1,578 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + + from CompositeType ct, int i, string name, Type tp + where component_types(ct, i, name, tp) + and not containsAliases(ct) + select ct, i, name, tp \ No newline at end of file diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/element_type.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/element_type.ql new file mode 100644 index 000000000000..32b9d6bef107 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/element_type.ql @@ -0,0 +1,578 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + + from CompositeType ct, Type et + where element_type(ct, et) + and not containsAliases(ct) + select ct, et \ No newline at end of file diff --git a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/go.dbscheme b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/go.dbscheme similarity index 100% rename from go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/go.dbscheme rename to go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/go.dbscheme diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/key_type.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/key_type.ql new file mode 100644 index 000000000000..8d1fe2f1ae5f --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/key_type.ql @@ -0,0 +1,578 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + + from MapType mt, Type kt + where key_type(mt, kt) + and not containsAliases(mt) + select mt, kt \ No newline at end of file diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/objecttypes.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/objecttypes.ql new file mode 100644 index 000000000000..0fd7fb2d99ad --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/objecttypes.ql @@ -0,0 +1,583 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + +class Object extends @object { + string toString() { result = "object" } +} + +from Object o, Type t +where objecttypes(o, t) +// Note this means that type alises really do have an object in the new database; +// they just have types that resolve to the target of the alias, not the alias itself. +select o, t.getDeepUnaliasedType() diff --git a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/old.dbscheme b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/old.dbscheme similarity index 99% rename from go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/old.dbscheme rename to go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/old.dbscheme index 60e1b7912d7c..40dfd9635451 100644 --- a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/old.dbscheme +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/old.dbscheme @@ -209,6 +209,9 @@ alias_rhs(unique int alias: @typealias ref, int tp: @type ref); #keyset[parent, index] component_types(int parent: @compositetype ref, int index: int ref, string name: string ref, int tp: @type ref); +#keyset[parent, index] +component_tags(int parent: @compositetype ref, int index: int ref, string tag: string ref); + array_length(unique int tp: @arraytype ref, string len: string ref); type_objects(unique int tp: @type ref, int object: @object ref); diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_objects.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_objects.ql new file mode 100644 index 000000000000..a4c783022b42 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_objects.ql @@ -0,0 +1,587 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL + + +class Object extends @object { + string toString() { result = "object" } +} + +// The schema for types and typename are: +// +// types(unique int id: @type, int kind: int ref); +// type_objects(unique int tp: @type ref, int object: @object ref); +from Type type, Object object +where + type_objects(type, object) + and not containsAliases(type) +select type, object diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_of.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_of.ql new file mode 100644 index 000000000000..1390b1b1b5d4 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_of.ql @@ -0,0 +1,581 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + +class Expr extends @expr { + string toString() { result = "expr" } +} + + from Expr e, Type t + where type_of(e, t) + select e, t.getDeepUnaliasedType() \ No newline at end of file diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/typename.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/typename.ql new file mode 100644 index 000000000000..451297d10e4d --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/typename.ql @@ -0,0 +1,583 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL + + +// The schema for types and typename are: +// +// types(unique int id: @type, int kind: int ref); +// typename(unique int tp: @type ref, string name: string ref); +from Type type, string name +where + typename(type, name) and + not containsAliases(type) +select type, name diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/types.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/types.ql new file mode 100644 index 000000000000..77371c92c960 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/types.ql @@ -0,0 +1,582 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL + + +// The schema for types is: +// +// types(unique int id: @type, int kind: int ref); +from Type type, int kind +where + types(type, kind) and + not containsAliases(type) +select type, kind diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/underlying_type.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/underlying_type.ql new file mode 100644 index 000000000000..0ee705b45eec --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/underlying_type.ql @@ -0,0 +1,579 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + +class NamedType extends @namedtype, Type {} + + from NamedType nt, Type ut + where underlying_type(nt, ut) + select nt, ut.getDeepUnaliasedType() \ No newline at end of file diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/update_lib_copies.py b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/update_lib_copies.py new file mode 100644 index 000000000000..c95758605ad2 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/update_lib_copies.py @@ -0,0 +1,40 @@ +import os +import glob + +thisdir = os.path.dirname(os.path.realpath(__file__)) + +toupdate = dict() + +startstr = "// BEGIN ALIASES.QLL" +endstr = "// END ALIASES.QLL" + +somelibcontentf = None +somelibcontent = None + +for f in glob.glob(os.path.join(thisdir, "*.ql")): + with open(f, "r") as fp: + content = fp.read() + idx = content.index(startstr) + if idx != 0 and idx != -1: + raise Exception("Expected file %s that contains aliases.qll to start with it (found it at offset %d)" % (f, idx)) + if idx == 0: + endidx = content.index(endstr) + if endidx == -1: + raise Exception("Expected file %s that contains aliases.qll to contain the end-of-library token %s" % (f, endstr)) + libcontent = content[idx : endidx + len(endstr)] + toupdate[f] = (content, libcontent) + somelibcontentf = f + somelibcontent = libcontent + +for (f, (content, libcontent)) in toupdate.items(); + if libcontent != somelibcontent: + raise Exception("Files that include aliases.qll disagree about its content (e.g., files %s and %s)" % (somelibcontentf, f)) + +print("Updating %d files that include aliases.qll" % len(toupdate)) + +with open(os.path.join(thisdir, "aliases.qll"), "r") as fp: + newlibcontent = fp.read().strip() + +for (f, (content, _)) in toupdate.items(): + with open(f, "w") as fp: + fp.write(newlibcontent + content[len(somelibcontent):]) diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/upgrade.properties b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/upgrade.properties new file mode 100644 index 000000000000..24aac75bda47 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/upgrade.properties @@ -0,0 +1,18 @@ +description: Remove support for type aliases +compatibility: full + +alias_rhs.rel: delete +array_length.rel: run array_length.qlo +base_type.rel: run base_type.qlo +component_tags.rel: delete +component_types.rel: run component_types.qlo +element_type.rel: run element_type.qlo +key_type.rel: run key_type.qlo +objecttypes.rel: run objecttypes.qlo +type_objects.rel: run type_objects.qlo +type_of.rel: run type_of.qlo +typename.rel: run typename.qlo +underlying_type.rel: run underlying_type.qlo +variadic.rel: run variadic.qlo +types.rel: run types.qlo + diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/variadic.ql b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/variadic.ql new file mode 100644 index 000000000000..4d93c94afd02 --- /dev/null +++ b/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/variadic.ql @@ -0,0 +1,577 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } + } + + /** A composite type, that is, not a basic type. */ + class CompositeType extends @compositetype, Type { } + + /** An array type. */ + class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } + } + + /** A slice type. */ + class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + // Improve efficiency of matching a struct to its unaliased equivalent + // by unpacking the first 5 fields and tags, allowing a single join + // to strongly constrain the available candidates. + private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) + } + + private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + + private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } + } + + private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } + } + + pragma[nomagic] + predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents + ) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) + } + + /** A struct type. */ + class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } + } + + /** A pointer type. */ + class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } + } + + private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + + private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } + } + + private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + component_types(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } + } + + pragma[nomagic] + predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) + } + + pragma[nomagic] + predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + ) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) + } + + /** An interface type. */ + class InterfaceType extends @interfacetype, CompositeType { + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, i, name, tp) | + component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + ( + i = 3 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp | component_types(this, -i, name, tp) | + component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | + nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + // Note no -1 here, because the first embedded type is at -1 + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + or + nEmbeds <= 2 + ) + } + } + + pragma[nomagic] + private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + } + + pragma[nomagic] + private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents + ) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) + } + + /** A tuple type. */ + class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + exists(Type tp | component_types(this, i, _, tp) | + component_types(tt, i, _, tp.getDeepUnaliasedType()) + ) + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } + } + + // Reasonably efficiently map from a signature type to its + // deep-unaliased equivalent, by using a single join for the leading 5 parameters + // and/or 3 results. + private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + + private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } + } + + pragma[nomagic] + private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) + } + + pragma[nomagic] + private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + ) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) + } + + /** A signature type. */ + class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } + } + + /** A map type. */ + class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } + } + + /** A channel type. */ + class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } + } + + /** A channel type that can only send. */ + class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can only receive. */ + class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** A channel type that can both send and receive. */ + class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } + } + + /** An alias type. */ + class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } + } + + /** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ + Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) + } + + predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL + + from Type t + where variadic(t) + and not containsAliases(t) + select t \ No newline at end of file diff --git a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/objects.ql b/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/objects.ql deleted file mode 100644 index a07513486852..000000000000 --- a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/objects.ql +++ /dev/null @@ -1,14 +0,0 @@ -class Type_ extends @type { - string toString() { result = "Type" } -} - -// The schema for types and typename are: -// -// types(unique int id: @type, int kind: int ref); -// objects(unique int id: @object, int kind: int ref, string name: string ref); -from Type_ type, int object, int kind -where - objects(type, object) and - types(type, kind) and - kind != 40 // @typealias -select type, object diff --git a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/type_objects.ql b/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/type_objects.ql deleted file mode 100644 index 8f37c41cab82..000000000000 --- a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/type_objects.ql +++ /dev/null @@ -1,18 +0,0 @@ -class Type_ extends @type { - string toString() { result = "Type" } -} - -class Object_ extends @object { - string toString() { result = "Object" } -} - -// The schema for types and typename are: -// -// types(unique int id: @type, int kind: int ref); -// type_objects(unique int tp: @type ref, int object: @object ref); -from Type_ type, Object_ object, int kind -where - type_objects(type, object) and - types(type, kind) and - kind != 40 // @typealias -select type, object diff --git a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/typename.ql b/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/typename.ql deleted file mode 100644 index d92ed426f067..000000000000 --- a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/typename.ql +++ /dev/null @@ -1,14 +0,0 @@ -class Type_ extends @type { - string toString() { result = "Type" } -} - -// The schema for types and typename are: -// -// types(unique int id: @type, int kind: int ref); -// typename(unique int tp: @type ref, string name: string ref); -from Type_ type, string name, int kind -where - typename(type, name) and - types(type, kind) and - kind != 40 // @typealias -select type, name diff --git a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/types.ql b/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/types.ql deleted file mode 100644 index 50be9e74a07d..000000000000 --- a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/types.ql +++ /dev/null @@ -1,12 +0,0 @@ -class Type_ extends @type { - string toString() { result = "Type" } -} - -// The schema for types is: -// -// types(unique int id: @type, int kind: int ref); -from Type_ type, int kind -where - types(type, kind) and - kind != 40 // @typealias -select type, kind diff --git a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/upgrade.properties b/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/upgrade.properties deleted file mode 100644 index fc4ebba17590..000000000000 --- a/go/downgrades/60e1b7912d7c68066b13c776b07c2da5fc13342a/upgrade.properties +++ /dev/null @@ -1,7 +0,0 @@ -description: Remove support for type aliases -compatibility: full - -alias_rhs.rel: delete -types.rel: run types.qlo -typename.rel: run typename.qlo -type_objects.rel: run type_objects.qlo diff --git a/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/component_tags.ql b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/component_tags.ql new file mode 100644 index 000000000000..7efd29b4ea53 --- /dev/null +++ b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/component_tags.ql @@ -0,0 +1,7 @@ +class StructType extends @structtype { + string toString() { result = "struct type" } +} + +from StructType st, int index +where component_types(st, index, _, _) +select st, index, "" diff --git a/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme index 60e1b7912d7c..40dfd9635451 100644 --- a/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme +++ b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme @@ -209,6 +209,9 @@ alias_rhs(unique int alias: @typealias ref, int tp: @type ref); #keyset[parent, index] component_types(int parent: @compositetype ref, int index: int ref, string name: string ref, int tp: @type ref); +#keyset[parent, index] +component_tags(int parent: @compositetype ref, int index: int ref, string tag: string ref); + array_length(unique int tp: @arraytype ref, string len: string ref); type_objects(unique int tp: @type ref, int object: @object ref); diff --git a/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/upgrade.properties b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/upgrade.properties index e4cdd2164e44..5786a2012470 100644 --- a/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/upgrade.properties +++ b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/upgrade.properties @@ -1,2 +1,3 @@ description: Add support for type aliases compatibility: full +component_tags.rel: run component_tags.qlo From f2a35d4ed1fdac8f3ae375387d21a5dcd1210fe6 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sun, 1 Sep 2024 22:58:41 +0100 Subject: [PATCH 19/36] Interface types: distinguish otherwise-identical interfaces with non-exported methods defined in different packages --- .../aliases.qll | 0 .../array_length.ql | 0 .../base_type.ql | 0 .../component_types.ql | 0 .../element_type.ql | 0 .../go.dbscheme | 0 .../key_type.ql | 0 .../objecttypes.ql | 0 .../old.dbscheme | 0 .../type_objects.ql | 0 .../type_of.ql | 0 .../typename.ql | 0 .../types.ql | 0 .../underlying_type.ql | 0 .../update_lib_copies.py | 0 .../upgrade.properties | 1 + .../variadic.ql | 0 go/extractor/dbscheme/tables.go | 7 ++++ go/extractor/extractor.go | 7 ++++ go/ql/lib/go.dbscheme | 3 ++ go/ql/lib/semmle/go/Types.qll | 34 +++++++++++++------ 21 files changed, 42 insertions(+), 10 deletions(-) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/aliases.qll (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/array_length.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/base_type.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/component_types.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/element_type.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/go.dbscheme (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/key_type.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/objecttypes.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/old.dbscheme (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/type_objects.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/type_of.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/typename.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/types.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/underlying_type.ql (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/update_lib_copies.py (100%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/upgrade.properties (93%) rename go/downgrades/{40dfd9635451090c49d1a4f2be8470005ea4a094 => 629b145fac466483e5eb38e1fd752f82cbb89196}/variadic.ql (100%) diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/aliases.qll b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/aliases.qll rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/array_length.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/array_length.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/base_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/base_type.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/component_types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/component_types.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/element_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/element_type.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/go.dbscheme b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/go.dbscheme similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/go.dbscheme rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/go.dbscheme diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/key_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/key_type.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/objecttypes.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/objecttypes.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/old.dbscheme b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/old.dbscheme similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/old.dbscheme rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/old.dbscheme diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_objects.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_objects.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_of.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/type_of.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/typename.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/typename.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/types.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/underlying_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/underlying_type.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/update_lib_copies.py b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/update_lib_copies.py rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/upgrade.properties b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties similarity index 93% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/upgrade.properties rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties index 24aac75bda47..9832e7fe4add 100644 --- a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/upgrade.properties +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties @@ -7,6 +7,7 @@ base_type.rel: run base_type.qlo component_tags.rel: delete component_types.rel: run component_types.qlo element_type.rel: run element_type.qlo +interface_private_method_ids: delete key_type.rel: run key_type.qlo objecttypes.rel: run objecttypes.qlo type_objects.rel: run type_objects.qlo diff --git a/go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/variadic.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql similarity index 100% rename from go/downgrades/40dfd9635451090c49d1a4f2be8470005ea4a094/variadic.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql diff --git a/go/extractor/dbscheme/tables.go b/go/extractor/dbscheme/tables.go index 74111f161ef1..d2e865d1dc55 100644 --- a/go/extractor/dbscheme/tables.go +++ b/go/extractor/dbscheme/tables.go @@ -1166,6 +1166,13 @@ var ComponentTagsTable = NewTable("component_tags", StringColumn("tag"), ).KeySet("parent", "index") +// InterfacePrivateMethodIdsTable is the table associating interface types with their private method ids +var InterfacePrivateMethodIdsTable = NewTable("interface_private_method_ids", + EntityColumn(InterfaceType, "interface"), + IntColumn("index"), + StringColumn("id"), +).KeySet("interface", "index") + // ArrayLengthTable is the table associating array types with their length (represented as a string // since Go array lengths are 64-bit and hence do not always fit into a QL integer) var ArrayLengthTable = NewTable("array_length", diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index a2aced3e9fcb..1747b205fc62 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1665,6 +1665,13 @@ func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases boo } extractComponentType(tw, lbl, i, meth.Name(), meth.Type(), transparentAliases) + + // meth.Id() will be equal to meth.Name() for an exported method, or + // packge-qualified otherwise. + privateMethodId := meth.Id() + if privateMethodId != meth.Name() { + dbscheme.InterfacePrivateMethodIdsTable.Emit(tw, lbl, i, privateMethodId) + } } for i := 0; i < tp.NumEmbeddeds(); i++ { component := tp.EmbeddedType(i) diff --git a/go/ql/lib/go.dbscheme b/go/ql/lib/go.dbscheme index 40dfd9635451..629b145fac46 100644 --- a/go/ql/lib/go.dbscheme +++ b/go/ql/lib/go.dbscheme @@ -212,6 +212,9 @@ component_types(int parent: @compositetype ref, int index: int ref, string name: #keyset[parent, index] component_tags(int parent: @compositetype ref, int index: int ref, string tag: string ref); +#keyset[interface, index] +interface_private_method_ids(int interface: @interfacetype ref, int index: int ref, string id: string ref); + array_length(unique int tp: @arraytype ref, string len: string ref); type_objects(unique int tp: @type ref, int object: @object ref); diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index e05c1f2a2054..d3792c428fd1 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -888,9 +888,21 @@ class TypeSetLiteralType extends @typesetliteraltype, CompositeType { override string toString() { result = "type set literal type" } } +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not exists(interface_private_method_ids(intf, idx, _)) and qualifiedName = name + ) +} + private newtype TOptInterfaceComponent = MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } private class OptInterfaceComponent extends TOptInterfaceComponent { OptInterfaceComponent getWithDeepUnaliasedType() { @@ -910,7 +922,7 @@ private class InterfaceComponent extends MkSomeIComponent { predicate isComponentOf(InterfaceType intf, int i) { exists(string name, Type tp | - component_types(intf, i, name, tp) and + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and this = MkSomeIComponent(name, tp) ) } @@ -922,8 +934,8 @@ predicate unpackInterfaceType( TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and ( if nComponents >= 1 then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) @@ -1082,8 +1094,8 @@ class InterfaceType extends @interfacetype, CompositeType { i = 5 or this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + exists(string name, Type tp | isInterfaceComponentWithQualifiedName(this, i, name, tp) | + isInterfaceComponentWithQualifiedName(unaliased, i, name, tp.getDeepUnaliasedType()) ) } @@ -1094,21 +1106,23 @@ class InterfaceType extends @interfacetype, CompositeType { i = 3 or this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + exists(string name, Type tp | isInterfaceComponentWithQualifiedName(this, -i, name, tp) | + isInterfaceComponentWithQualifiedName(unaliased, -i, name, tp.getDeepUnaliasedType()) ) } override InterfaceType getDeepUnaliasedType() { result = this.getDeepUnaliasedTypeCandidate() and exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) + nComponents = count(int i | isInterfaceComponentWithQualifiedName(this, i, _, _) and i >= 0) | this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) or nComponents <= 5 ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | + exists(int nEmbeds | + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(this, i, _, _) and i < 0) + | // Note no -1 here, because the first embedded type is at -1 this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) or From ac393764cdc787e01e1523c6ac490d1c045d2629 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sun, 1 Sep 2024 22:59:17 +0100 Subject: [PATCH 20/36] autoformat and tidy an unnecessary direct db relation use --- go/ql/lib/semmle/go/Types.qll | 38 +++++++++++------------------------ 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index d3792c428fd1..5720f906c756 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -1201,30 +1201,20 @@ class ComparableType extends NamedType { } pragma[nomagic] -private predicate unpackTupleType(TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents) { +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { nComponents = count(int i | component_types(tt, i, _, _)) and - ( - if nComponents >= 1 - then c0 = MkSomeType(tt.getComponentType(0)) - else c0 = MkNoType() - ) and - ( - if nComponents >= 2 - then c1 = MkSomeType(tt.getComponentType(1)) - else c1 = MkNoType() - ) and - ( - if nComponents >= 3 - then c2 = MkSomeType(tt.getComponentType(2)) - else c2 = MkNoType() - ) + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) } pragma[nomagic] -private predicate unpackAndUnaliasTupleType(TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents) { - exists( - OptType c0a, OptType c1a, OptType c2a - | +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | unpackTupleType(tt, c0a, c1a, c2a, nComponents) and c0 = c0a.getDeepUnaliasedType() and c1 = c1a.getDeepUnaliasedType() and @@ -1238,9 +1228,7 @@ class TupleType extends @tupletype, CompositeType { Type getComponentType(int i) { component_types(this, i, _, result) } private TupleType getCandidateDeepUnaliasedType() { - exists( - OptType c0, OptType c1, OptType c2, int nComponents - | + exists(OptType c0, OptType c1, OptType c2, int nComponents | unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and unpackTupleType(result, c0, c1, c2, nComponents) ) @@ -1254,9 +1242,7 @@ class TupleType extends @tupletype, CompositeType { or this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() } override TupleType getDeepUnaliasedType() { From 1609aa5faf4fa12bcae482d470daa8c5edd5f1b0 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Sun, 1 Sep 2024 23:04:42 +0100 Subject: [PATCH 21/36] Interface unaliasing: don't confuse the empty interface with the type 'comparable' --- go/ql/lib/semmle/go/Types.qll | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 5720f906c756..b3302b90cf27 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -932,10 +932,12 @@ pragma[nomagic] predicate unpackInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + (if intf.isOrEmbedsComparable() then isComparable = true else isComparable = false) and ( if nComponents >= 1 then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) @@ -977,14 +979,15 @@ pragma[nomagic] predicate unpackAndUnaliasInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { exists( OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, OptInterfaceComponent e2a | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and c0 = c0a.getWithDeepUnaliasedType() and c1 = c1a.getWithDeepUnaliasedType() and c2 = c2a.getWithDeepUnaliasedType() and @@ -1080,10 +1083,11 @@ class InterfaceType extends @interfacetype, CompositeType { exists( OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) ) } From 77321e663b3f77102754a30e06571774cedd311d Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 11:25:37 +0100 Subject: [PATCH 22/36] Downgrades de-alising library: efficiency fixes --- .../aliases.qll | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll index 33de6e892773..58f763712cdc 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll @@ -271,6 +271,20 @@ predicate unpackAndUnaliasInterfaceType( /** An interface type. */ class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and component_types(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and component_types(this, -(index + 1), _, tp) + } + private InterfaceType getDeepUnaliasedTypeCandidate() { exists( OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, @@ -289,35 +303,32 @@ class InterfaceType extends @interfacetype, CompositeType { i = 5 or this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() ) } private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and + i >= 2 and ( - i = 3 or + i = 2 or this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) ) } override InterfaceType getDeepUnaliasedType() { result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) or nComponents <= 5 ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) or nEmbeds <= 2 ) @@ -366,9 +377,7 @@ class TupleType extends @tupletype, CompositeType { or this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) + tt.getComponentType(i).getDeepUnaliasedType() = this.getComponentType(i) } override TupleType getDeepUnaliasedType() { From 89abd53902e33af21a39ffb9230d3f6b9c49fe87 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 11:51:44 +0100 Subject: [PATCH 23/36] Fix --- go/ql/lib/semmle/go/Types.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index b3302b90cf27..a13be5d63ad3 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -894,7 +894,7 @@ private predicate isInterfaceComponentWithQualifiedName( exists(string name | component_types(intf, idx, name, tp) | interface_private_method_ids(intf, idx, qualifiedName) or - not exists(interface_private_method_ids(intf, idx, _)) and qualifiedName = name + not interface_private_method_ids(intf, idx, _) and qualifiedName = name ) } From 4a1f412c12c0ef471d311353589ca463c634648b Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 12:10:23 +0100 Subject: [PATCH 24/36] Port Types.qll fixes to the downgrade scripts, and fix a trivial TupleType deep-unalias bug --- .../aliases.qll | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll index 58f763712cdc..8f5f30b2850b 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll @@ -174,9 +174,21 @@ class PointerType extends @pointertype, CompositeType { } } +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + private newtype TOptInterfaceComponent = MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } private class OptInterfaceComponent extends TOptInterfaceComponent { OptInterfaceComponent getWithDeepUnaliasedType() { @@ -196,7 +208,7 @@ private class InterfaceComponent extends MkSomeIComponent { predicate isComponentOf(InterfaceType intf, int i) { exists(string name, Type tp | - component_types(intf, i, name, tp) and + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and this = MkSomeIComponent(name, tp) ) } @@ -206,10 +218,16 @@ pragma[nomagic] predicate unpackInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and ( if nComponents >= 1 then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) @@ -251,14 +269,15 @@ pragma[nomagic] predicate unpackAndUnaliasInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { exists( OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, OptInterfaceComponent e2a | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and c0 = c0a.getWithDeepUnaliasedType() and c1 = c1a.getWithDeepUnaliasedType() and c2 = c2a.getWithDeepUnaliasedType() and @@ -272,7 +291,7 @@ predicate unpackAndUnaliasInterfaceType( /** An interface type. */ class InterfaceType extends @interfacetype, CompositeType { private Type getMethodType(int i, string name) { - i >= 0 and component_types(this, i, name, result) + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) } /** @@ -282,17 +301,18 @@ class InterfaceType extends @interfacetype, CompositeType { * interface type. */ private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and component_types(this, -(index + 1), _, tp) + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) } private InterfaceType getDeepUnaliasedTypeCandidate() { exists( OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) ) } @@ -377,7 +397,7 @@ class TupleType extends @tupletype, CompositeType { or this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - tt.getComponentType(i).getDeepUnaliasedType() = this.getComponentType(i) + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() } override TupleType getDeepUnaliasedType() { @@ -558,6 +578,18 @@ class SendRecvChanType extends @sendrcvchantype, ChanType { } } +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + /** An alias type. */ class AliasType extends @typealias, CompositeType { /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ From 22ff05d0496847842112e7100932ac81a6c3a6a3 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 15:00:53 +0100 Subject: [PATCH 25/36] Downgrade script typo --- .../update_lib_copies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py index c95758605ad2..f9306b1c40aa 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py @@ -26,7 +26,7 @@ somelibcontentf = f somelibcontent = libcontent -for (f, (content, libcontent)) in toupdate.items(); +for (f, (content, libcontent)) in toupdate.items(): if libcontent != somelibcontent: raise Exception("Files that include aliases.qll disagree about its content (e.g., files %s and %s)" % (somelibcontentf, f)) From 0d3a0d94f1a929875d9d667547bc4b3d4c3f31ff Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 15:01:21 +0100 Subject: [PATCH 26/36] Update downgrade scripts --- .../array_length.ql | 1105 ++++++++-------- .../base_type.ql | 1105 ++++++++-------- .../component_types.ql | 1106 +++++++++-------- .../element_type.ql | 1106 +++++++++-------- .../key_type.ql | 1106 +++++++++-------- .../objecttypes.ql | 1097 ++++++++-------- .../old.dbscheme | 3 + .../type_objects.ql | 97 +- .../type_of.ql | 1103 ++++++++-------- .../typename.ql | 93 +- .../types.ql | 93 +- .../underlying_type.ql | 1102 ++++++++-------- .../variadic.ql | 1105 ++++++++-------- 13 files changed, 5350 insertions(+), 4871 deletions(-) diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql index 3850a63a4657..0d8aa37b8ee9 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql @@ -2,576 +2,617 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } - } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - - from ArrayType at, string length - where array_length(at, length) - and not containsAliases(at) - select at, length \ No newline at end of file +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL +from ArrayType at, string length +where + array_length(at, length) and + not containsAliases(at) +select at, length diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql index ca548f02a20d..5f96a8558ff1 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql @@ -2,576 +2,617 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - - from PointerType pt, Type base - where base_type(pt, base) - and not containsAliases(pt) - select pt, base \ No newline at end of file +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL +from PointerType pt, Type base +where + base_type(pt, base) and + not containsAliases(pt) +select pt, base diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql index 2f0dd0e5bd39..f17ed42901a5 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql @@ -2,577 +2,617 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - - - from CompositeType ct, int i, string name, Type tp - where component_types(ct, i, name, tp) - and not containsAliases(ct) - select ct, i, name, tp \ No newline at end of file +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL +from CompositeType ct, int i, string name, Type tp +where + component_types(ct, i, name, tp) and + not containsAliases(ct) +select ct, i, name, tp diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql index 32b9d6bef107..8f9ad3912aba 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql @@ -2,577 +2,617 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - - - from CompositeType ct, Type et - where element_type(ct, et) - and not containsAliases(ct) - select ct, et \ No newline at end of file +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL +from CompositeType ct, Type et +where + element_type(ct, et) and + not containsAliases(ct) +select ct, et diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql index 8d1fe2f1ae5f..36748ad1825b 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql @@ -2,577 +2,617 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - - - from MapType mt, Type kt - where key_type(mt, kt) - and not containsAliases(mt) - select mt, kt \ No newline at end of file +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL +from MapType mt, Type kt +where + key_type(mt, kt) and + not containsAliases(mt) +select mt, kt diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql index 0fd7fb2d99ad..584eda347c41 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql @@ -2,578 +2,617 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL class Object extends @object { - string toString() { result = "object" } + string toString() { result = "object" } } from Object o, Type t diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/old.dbscheme b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/old.dbscheme index 40dfd9635451..629b145fac46 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/old.dbscheme +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/old.dbscheme @@ -212,6 +212,9 @@ component_types(int parent: @compositetype ref, int index: int ref, string name: #keyset[parent, index] component_tags(int parent: @compositetype ref, int index: int ref, string tag: string ref); +#keyset[interface, index] +interface_private_method_ids(int interface: @interfacetype ref, int index: int ref, string id: string ref); + array_length(unique int tp: @arraytype ref, string len: string ref); type_objects(unique int tp: @type ref, int object: @object ref); diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql index a4c783022b42..cf4c0f587e9f 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql @@ -174,9 +174,21 @@ class PointerType extends @pointertype, CompositeType { } } +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + private newtype TOptInterfaceComponent = MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } private class OptInterfaceComponent extends TOptInterfaceComponent { OptInterfaceComponent getWithDeepUnaliasedType() { @@ -196,7 +208,7 @@ private class InterfaceComponent extends MkSomeIComponent { predicate isComponentOf(InterfaceType intf, int i) { exists(string name, Type tp | - component_types(intf, i, name, tp) and + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and this = MkSomeIComponent(name, tp) ) } @@ -206,10 +218,16 @@ pragma[nomagic] predicate unpackInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and ( if nComponents >= 1 then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) @@ -251,14 +269,15 @@ pragma[nomagic] predicate unpackAndUnaliasInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { exists( OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, OptInterfaceComponent e2a | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and c0 = c0a.getWithDeepUnaliasedType() and c1 = c1a.getWithDeepUnaliasedType() and c2 = c2a.getWithDeepUnaliasedType() and @@ -271,14 +290,29 @@ predicate unpackAndUnaliasInterfaceType( /** An interface type. */ class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + private InterfaceType getDeepUnaliasedTypeCandidate() { exists( OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) ) } @@ -289,35 +323,32 @@ class InterfaceType extends @interfacetype, CompositeType { i = 5 or this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() ) } private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and + i >= 2 and ( - i = 3 or + i = 2 or this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) ) } override InterfaceType getDeepUnaliasedType() { result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) or nComponents <= 5 ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) or nEmbeds <= 2 ) @@ -366,9 +397,7 @@ class TupleType extends @tupletype, CompositeType { or this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() } override TupleType getDeepUnaliasedType() { @@ -549,6 +578,18 @@ class SendRecvChanType extends @sendrcvchantype, ChanType { } } +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + /** An alias type. */ class AliasType extends @typealias, CompositeType { /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ @@ -570,8 +611,6 @@ Type unalias(Type t) { predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } // END ALIASES.QLL - - class Object extends @object { string toString() { result = "object" } } @@ -582,6 +621,6 @@ class Object extends @object { // type_objects(unique int tp: @type ref, int object: @object ref); from Type type, Object object where - type_objects(type, object) - and not containsAliases(type) + type_objects(type, object) and + not containsAliases(type) select type, object diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql index 1390b1b1b5d4..511d32d5a7e0 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql @@ -2,580 +2,619 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL class Expr extends @expr { - string toString() { result = "expr" } + string toString() { result = "expr" } } - from Expr e, Type t - where type_of(e, t) - select e, t.getDeepUnaliasedType() \ No newline at end of file +from Expr e, Type t +where type_of(e, t) +select e, t.getDeepUnaliasedType() diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql index 451297d10e4d..520a0d9e2f6e 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql @@ -174,9 +174,21 @@ class PointerType extends @pointertype, CompositeType { } } +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + private newtype TOptInterfaceComponent = MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } private class OptInterfaceComponent extends TOptInterfaceComponent { OptInterfaceComponent getWithDeepUnaliasedType() { @@ -196,7 +208,7 @@ private class InterfaceComponent extends MkSomeIComponent { predicate isComponentOf(InterfaceType intf, int i) { exists(string name, Type tp | - component_types(intf, i, name, tp) and + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and this = MkSomeIComponent(name, tp) ) } @@ -206,10 +218,16 @@ pragma[nomagic] predicate unpackInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and ( if nComponents >= 1 then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) @@ -251,14 +269,15 @@ pragma[nomagic] predicate unpackAndUnaliasInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { exists( OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, OptInterfaceComponent e2a | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and c0 = c0a.getWithDeepUnaliasedType() and c1 = c1a.getWithDeepUnaliasedType() and c2 = c2a.getWithDeepUnaliasedType() and @@ -271,14 +290,29 @@ predicate unpackAndUnaliasInterfaceType( /** An interface type. */ class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + private InterfaceType getDeepUnaliasedTypeCandidate() { exists( OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) ) } @@ -289,35 +323,32 @@ class InterfaceType extends @interfacetype, CompositeType { i = 5 or this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() ) } private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and + i >= 2 and ( - i = 3 or + i = 2 or this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) ) } override InterfaceType getDeepUnaliasedType() { result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) or nComponents <= 5 ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) or nEmbeds <= 2 ) @@ -366,9 +397,7 @@ class TupleType extends @tupletype, CompositeType { or this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() } override TupleType getDeepUnaliasedType() { @@ -549,6 +578,18 @@ class SendRecvChanType extends @sendrcvchantype, ChanType { } } +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + /** An alias type. */ class AliasType extends @typealias, CompositeType { /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ @@ -570,8 +611,6 @@ Type unalias(Type t) { predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } // END ALIASES.QLL - - // The schema for types and typename are: // // types(unique int id: @type, int kind: int ref); diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql index 77371c92c960..50f9d5e32bb3 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql @@ -174,9 +174,21 @@ class PointerType extends @pointertype, CompositeType { } } +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + private newtype TOptInterfaceComponent = MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } private class OptInterfaceComponent extends TOptInterfaceComponent { OptInterfaceComponent getWithDeepUnaliasedType() { @@ -196,7 +208,7 @@ private class InterfaceComponent extends MkSomeIComponent { predicate isComponentOf(InterfaceType intf, int i) { exists(string name, Type tp | - component_types(intf, i, name, tp) and + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and this = MkSomeIComponent(name, tp) ) } @@ -206,10 +218,16 @@ pragma[nomagic] predicate unpackInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and ( if nComponents >= 1 then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) @@ -251,14 +269,15 @@ pragma[nomagic] predicate unpackAndUnaliasInterfaceType( InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable ) { exists( OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, OptInterfaceComponent e2a | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and c0 = c0a.getWithDeepUnaliasedType() and c1 = c1a.getWithDeepUnaliasedType() and c2 = c2a.getWithDeepUnaliasedType() and @@ -271,14 +290,29 @@ predicate unpackAndUnaliasInterfaceType( /** An interface type. */ class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + private InterfaceType getDeepUnaliasedTypeCandidate() { exists( OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) ) } @@ -289,35 +323,32 @@ class InterfaceType extends @interfacetype, CompositeType { i = 5 or this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() ) } private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and + i >= 2 and ( - i = 3 or + i = 2 or this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) ) } override InterfaceType getDeepUnaliasedType() { result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) or nComponents <= 5 ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) or nEmbeds <= 2 ) @@ -366,9 +397,7 @@ class TupleType extends @tupletype, CompositeType { or this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() } override TupleType getDeepUnaliasedType() { @@ -549,6 +578,18 @@ class SendRecvChanType extends @sendrcvchantype, ChanType { } } +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + /** An alias type. */ class AliasType extends @typealias, CompositeType { /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ @@ -570,8 +611,6 @@ Type unalias(Type t) { predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } // END ALIASES.QLL - - // The schema for types is: // // types(unique int id: @type, int kind: int ref); diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql index 0ee705b45eec..bb857e8ad221 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql @@ -2,578 +2,616 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} -class NamedType extends @namedtype, Type {} +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL - from NamedType nt, Type ut - where underlying_type(nt, ut) - select nt, ut.getDeepUnaliasedType() \ No newline at end of file +from NamedType nt, Type ut +where underlying_type(nt, ut) +select nt, ut.getDeepUnaliasedType() diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql index 4d93c94afd02..f926a7725acc 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql @@ -2,576 +2,617 @@ // Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. /** A Go type. */ class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } - } - - /** A composite type, that is, not a basic type. */ - class CompositeType extends @compositetype, Type { } - - /** An array type. */ - class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() } - - /** A slice type. */ - class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - // Improve efficiency of matching a struct to its unaliased equivalent - // by unpacking the first 5 fields and tags, allowing a single join - // to strongly constrain the available candidates. - private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) } - - private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - - private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) } - - private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) } - - pragma[nomagic] - predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) ) } - - pragma[nomagic] - predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents - ) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 ) } - - /** A struct type. */ - class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() } - - /** A pointer type. */ - class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) } - - private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { component_types(any(InterfaceType i), _, name, tp) } - - private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) } - - private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - component_types(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) } - - pragma[nomagic] - predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { - nComponents = count(int i | component_types(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | component_types(intf, i, _, _) and i < 0) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 ) } - - pragma[nomagic] - predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds - ) { +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) ) } - - /** An interface type. */ - class InterfaceType extends @interfacetype, CompositeType { - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, i, name, tp) | - component_types(unaliased, i, name, tp.getDeepUnaliasedType()) - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - ( - i = 3 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp | component_types(this, -i, name, tp) | - component_types(unaliased, -i, name, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | - nComponents = count(int i | component_types(this, i, _, _) and i >= 0) - | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | component_types(this, i, _, _) and i < 0) | - // Note no -1 here, because the first embedded type is at -1 - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds) - or - nEmbeds <= 2 - ) - } - } - - pragma[nomagic] - private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() } - - pragma[nomagic] - private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents - ) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() } - - /** A tuple type. */ - class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | ( - i = 3 + nParams <= 5 or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) ) and - exists(Type tp | component_types(this, i, _, tp) | - component_types(tt, i, _, tp.getDeepUnaliasedType()) - ) - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + ( + nResults <= 3 or - nComponents <= 3 + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) ) - } - } - - // Reasonably efficiently map from a signature type to its - // deep-unaliased equivalent, by using a single join for the leading 5 parameters - // and/or 3 results. - private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - - private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } - } - - pragma[nomagic] - private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) - } - - pragma[nomagic] - private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - ) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() ) } - - /** A signature type. */ - class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } - } - - /** A map type. */ - class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } - } - - /** A channel type. */ - class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } - } - - /** A channel type that can only send. */ - class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } - } - - /** A channel type that can only receive. */ - class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() } - - /** A channel type that can both send and receive. */ - class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** An alias type. */ - class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - /** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ - Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() } - - predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - // END ALIASES.QLL - - from Type t - where variadic(t) - and not containsAliases(t) - select t \ No newline at end of file +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } +// END ALIASES.QLL +from Type t +where + variadic(t) and + not containsAliases(t) +select t From a0d609aaf49bc09d837b36539dc735c9f499d36e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 19:09:14 +0100 Subject: [PATCH 27/36] Ensure fields are created for de-aliased struct types This means that there is a target for defs and refs to refer to after the original fields go away because their corresponding structs have also gone away on a database downgrade. --- go/extractor/extractor.go | 32 ++++++++++++++++++++------------ go/extractor/trap/labels.go | 18 +++++++++++------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 1747b205fc62..dec88c8708ec 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1625,21 +1625,29 @@ func extractTypeWithFlags(tw *trap.Writer, tp types.Type, transparentAliases boo for i := 0; i < tp.NumFields(); i++ { field := tp.Field(i) - if !transparentAliases { - // ensure the field is associated with a label - note that - // struct fields do not have a parent scope, so they are not - // dealt with by `extractScopes`. - - // Skip this when extracting a type with transparent aliases; - // this is not the definitive version of the type. - fieldlbl, exists := tw.Labeler.FieldID(field, i, lbl) - if !exists { - extractObject(tw, field, fieldlbl) - } + // ensure the field is associated with a label - note that + // struct fields do not have a parent scope, so they are not + // dealt with by `extractScopes`. + + // For the transparentAliases case we bypass the object-label cache + // because we're extracting a field relative to a synthetic field + // that has a different type and therefore label, whereas the label + // cache is indexed by object, not type-label. + var fieldlbl trap.Label + var exists bool + if transparentAliases { + fieldlbl = tw.Labeler.FieldIDNoCache(field, i, lbl) + exists = false + } else { + fieldlbl, exists = tw.Labeler.FieldID(field, i, lbl) + } - dbscheme.FieldStructsTable.Emit(tw, fieldlbl, lbl) + if !exists { + extractObject(tw, field, fieldlbl) } + dbscheme.FieldStructsTable.Emit(tw, fieldlbl, lbl) + name := field.Name() if field.Embedded() { name = "" diff --git a/go/extractor/trap/labels.go b/go/extractor/trap/labels.go index d9d82679023d..c843fac5c478 100644 --- a/go/extractor/trap/labels.go +++ b/go/extractor/trap/labels.go @@ -210,6 +210,16 @@ func (l *Labeler) ReceiverObjectID(object types.Object, methlbl Label) (Label, b return label, exists } +func (l *Labeler) FieldIDNoCache(field *types.Var, idx int, structlbl Label) Label { + name := field.Name() + // there can be multiple fields with the blank identifier, so use index to + // distinguish them + if field.Name() == "_" { + name = fmt.Sprintf("_%d", idx) + } + return l.GlobalID(fmt.Sprintf("{%v},%s;field", structlbl, name)) +} + // FieldID associates a label with the given field and returns it, together with // a flag indicating whether the field already had a label associated with it; // the field must belong to `structlbl`, since that label is used to construct @@ -218,13 +228,7 @@ func (l *Labeler) ReceiverObjectID(object types.Object, methlbl Label) (Label, b func (l *Labeler) FieldID(field *types.Var, idx int, structlbl Label) (Label, bool) { label, exists := l.objectLabels[field] if !exists { - name := field.Name() - // there can be multiple fields with the blank identifier, so use index to - // distinguish them - if field.Name() == "_" { - name = fmt.Sprintf("_%d", idx) - } - label = l.GlobalID(fmt.Sprintf("{%v},%s;field", structlbl, name)) + label = l.FieldIDNoCache(field, idx, structlbl) l.objectLabels[field] = label } return label, exists From 37bb6dc3383104781fe4775fc57e3dd6a64de74c Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 19:11:35 +0100 Subject: [PATCH 28/36] Add space to aliases.qll to cooperate with autoformat --- .../629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql | 1 + go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql | 1 + .../629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql | 1 + 13 files changed, 13 insertions(+) diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll index 8f5f30b2850b..2ecdedcb0f34 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll @@ -610,4 +610,5 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql index 0d8aa37b8ee9..679b73fef76a 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL from ArrayType at, string length where diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql index 5f96a8558ff1..2d1b00ce3a60 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL from PointerType pt, Type base where diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql index f17ed42901a5..d828bc6cd259 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL from CompositeType ct, int i, string name, Type tp where diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql index 8f9ad3912aba..34270bbcd82a 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL from CompositeType ct, Type et where diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql index 36748ad1825b..61e79dddbd67 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL from MapType mt, Type kt where diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql index 584eda347c41..b22dcb76f499 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL class Object extends @object { string toString() { result = "object" } diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql index cf4c0f587e9f..01c31c974033 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL class Object extends @object { string toString() { result = "object" } diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql index 511d32d5a7e0..20b86949f47e 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL class Expr extends @expr { string toString() { result = "expr" } diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql index 520a0d9e2f6e..8f9dc9bb5d90 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL // The schema for types and typename are: // diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql index 50f9d5e32bb3..77a0850b4a9c 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL // The schema for types is: // diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql index bb857e8ad221..3def6be60be9 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL from NamedType nt, Type ut diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql index f926a7725acc..9d06a63ab1aa 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql @@ -610,6 +610,7 @@ Type unalias(Type t) { } predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + // END ALIASES.QLL from Type t where From d1153392c20cf2f1d3c3439d640b415b68cfa33e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 19:12:02 +0100 Subject: [PATCH 29/36] Improve downgrade script to produce a consistent database --- .../defs.ql | 644 ++++++++++++++++++ .../fieldstructs.ql | 624 +++++++++++++++++ .../objects.ql | 623 +++++++++++++++++ .../objecttypes.ql | 1 + .../typeparam.ql | 625 +++++++++++++++++ .../upgrade.properties | 8 +- .../uses.ql | 644 ++++++++++++++++++ 7 files changed, 3167 insertions(+), 2 deletions(-) create mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/defs.ql create mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql create mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql create mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql create mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/defs.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/defs.ql new file mode 100644 index 000000000000..5fa8e35720e4 --- /dev/null +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/defs.ql @@ -0,0 +1,644 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and + ( + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + +// END ALIASES.QLL + +class Object extends @object { + string toString() { result = "object" } +} + +class Ident extends @ident { + string toString() { result = "identifier" } +} + +// Redirect references to e.g. a struct field `x MyInt` +// onto the corresponding field `x int` of the unaliased type. +Object getReplacementField(Object o) { + exists(StructType st, StructType unaliasedSt, string name | + fieldstructs(o, st) and + unaliasedSt = st.getDeepUnaliasedType() and + objects(o, _, name) and + fieldstructs(result, unaliasedSt) and + objects(result, _, name) + ) +} + +from Ident i, Object o, Object replacementO +where + defs(i, o) and + ( + replacementO = getReplacementField(o) + or + not exists(getReplacementField(o)) and replacementO = o + ) +select i, replacementO diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql new file mode 100644 index 000000000000..c9e133de2612 --- /dev/null +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql @@ -0,0 +1,624 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and + ( + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + +// END ALIASES.QLL + +class Object extends @object { + string toString() { result = "object" } +} + +from Object field, StructType st +where + fieldstructs(field, st) and + not containsAliases(st) +select field, st diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql new file mode 100644 index 000000000000..1513eaf2aa4e --- /dev/null +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql @@ -0,0 +1,623 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and + ( + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + +// END ALIASES.QLL +class Object extends @object { + string toString() { result = "object" } +} + +from Object o, int kind, string name +where + objects(o, kind, name) and + not exists(StructType st | fieldstructs(o, st) and containsAliases(st)) +select o, kind, name diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql index b22dcb76f499..889414881876 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql @@ -618,6 +618,7 @@ class Object extends @object { from Object o, Type t where objecttypes(o, t) +and not exists(StructType st | fieldstructs(o, st) and containsAliases(st)) // Note this means that type alises really do have an object in the new database; // they just have types that resolve to the target of the alias, not the alias itself. select o, t.getDeepUnaliasedType() diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql new file mode 100644 index 000000000000..667de3090f4f --- /dev/null +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql @@ -0,0 +1,625 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and + ( + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + +// END ALIASES.QLL +class TypeParamType extends @typeparamtype { + string toString() { result = "type parameter" } +} + +class TypeParamParentObject extends @typeparamparentobject { + string toString() { result = "type parameter parent object" } +} + +from TypeParamType tp, string name, CompositeType bound, TypeParamParentObject parent, int idx +where typeparam(tp, name, bound, parent, idx) +select tp, name, bound.getDeepUnaliasedType(), parent, idx diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties index 9832e7fe4add..1a36d02c5e49 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties @@ -6,14 +6,18 @@ array_length.rel: run array_length.qlo base_type.rel: run base_type.qlo component_tags.rel: delete component_types.rel: run component_types.qlo +defs.rel: run defs.qlo element_type.rel: run element_type.qlo +fieldstructs.rel: run fieldstructs.qlo interface_private_method_ids: delete key_type.rel: run key_type.qlo +objects.rel: run objects.qlo objecttypes.rel: run objecttypes.qlo type_objects.rel: run type_objects.qlo type_of.rel: run type_of.qlo typename.rel: run typename.qlo +typeparam.rel: run typeparam.qlo +types.rel: run types.qlo underlying_type.rel: run underlying_type.qlo +uses.rel: run uses.qlo variadic.rel: run variadic.qlo -types.rel: run types.qlo - diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql new file mode 100644 index 000000000000..0b40e2253a32 --- /dev/null +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql @@ -0,0 +1,644 @@ +// BEGIN ALIASES.QLL +// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. +/** A Go type. */ +class Type extends @type { + /** + * Gets this type with all aliases substituted for their underlying type. + * + * Note named types are not substituted. + */ + Type getDeepUnaliasedType() { result = this } + + /** + * Gets a basic textual representation of this type. + */ + string toString() { result = "type" } +} + +/** A composite type, that is, not a basic type. */ +class CompositeType extends @compositetype, Type { } + +/** An array type. */ +class ArrayType extends @arraytype, CompositeType { + /** Gets the element type of this array type. */ + Type getElementType() { element_type(this, result) } + + /** Gets the length of this array type as a string. */ + string getLengthString() { array_length(this, result) } + + override ArrayType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() and + result.getLengthString() = this.getLengthString() + } +} + +/** A slice type. */ +class SliceType extends @slicetype, CompositeType { + /** Gets the element type of this slice type. */ + Type getElementType() { element_type(this, result) } + + override SliceType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +// Improve efficiency of matching a struct to its unaliased equivalent +// by unpacking the first 5 fields and tags, allowing a single join +// to strongly constrain the available candidates. +private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { + component_types(s, i, name, tp) and component_tags(s, i, tag) +} + +private newtype TOptStructComponent = + MkNoComponent() or + MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } + +private class OptStructComponent extends TOptStructComponent { + OptStructComponent getWithDeepUnaliasedType() { + this = MkNoComponent() and result = MkNoComponent() + or + exists(string name, Type tp, string tag | + this = MkSomeComponent(name, tp, tag) and + result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) + ) + } + + string toString() { result = "struct component" } +} + +private class StructComponent extends MkSomeComponent { + string toString() { result = "struct component" } + + predicate isComponentOf(StructType s, int i) { + exists(string name, Type tp, string tag | + hasComponentTypeAndTag(s, i, name, tp, tag) and + this = MkSomeComponent(name, tp, tag) + ) + } +} + +pragma[nomagic] +predicate unpackStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + nComponents = count(int i | component_types(s, i, _, _)) and + ( + if nComponents >= 1 + then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) + else c0 = MkNoComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) + else c1 = MkNoComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) + else c2 = MkNoComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) + else c3 = MkNoComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) + else c4 = MkNoComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasStructType( + StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, + TOptStructComponent c3, TOptStructComponent c4, int nComponents +) { + exists( + OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, + OptStructComponent c4a + | + unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() + ) +} + +/** A struct type. */ +class StructType extends @structtype, CompositeType { + private StructType getDeepUnaliasedTypeCandidate() { + exists( + OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, + OptStructComponent c4, int nComponents + | + unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and + unpackStructType(result, c0, c1, c2, c3, c4, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { + // Note we must use component_types not hasOwnField here because component_types may specify + // interface-in-struct embedding, but hasOwnField does not return such members. + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) + ) and + exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | + hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) + ) + } + + override StructType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) + } +} + +/** A pointer type. */ +class PointerType extends @pointertype, CompositeType { + /** Gets the base type of this pointer type. */ + Type getBaseType() { base_type(this, result) } + + override PointerType getDeepUnaliasedType() { + result.getBaseType() = this.getBaseType().getDeepUnaliasedType() + } +} + +private predicate isInterfaceComponentWithQualifiedName( + InterfaceType intf, int idx, string qualifiedName, Type tp +) { + exists(string name | component_types(intf, idx, name, tp) | + interface_private_method_ids(intf, idx, qualifiedName) + or + not interface_private_method_ids(intf, idx, _) and qualifiedName = name + ) +} + +private newtype TOptInterfaceComponent = + MkNoIComponent() or + MkSomeIComponent(string name, Type tp) { + isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) + } + +private class OptInterfaceComponent extends TOptInterfaceComponent { + OptInterfaceComponent getWithDeepUnaliasedType() { + this = MkNoIComponent() and result = MkNoIComponent() + or + exists(string name, Type tp | + this = MkSomeIComponent(name, tp) and + result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) + ) + } + + string toString() { result = "interface component" } +} + +private class InterfaceComponent extends MkSomeIComponent { + string toString() { result = "interface component" } + + predicate isComponentOf(InterfaceType intf, int i) { + exists(string name, Type tp | + isInterfaceComponentWithQualifiedName(intf, i, name, tp) and + this = MkSomeIComponent(name, tp) + ) + } +} + +pragma[nomagic] +predicate unpackInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and + nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and + ( + if intf = any(ComparableType comparable).getBaseType() + then isComparable = true + else isComparable = false + ) and + ( + if nComponents >= 1 + then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) + else c0 = MkNoIComponent() + ) and + ( + if nComponents >= 2 + then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) + else c1 = MkNoIComponent() + ) and + ( + if nComponents >= 3 + then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) + else c2 = MkNoIComponent() + ) and + ( + if nComponents >= 4 + then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) + else c3 = MkNoIComponent() + ) and + ( + if nComponents >= 5 + then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) + else c4 = MkNoIComponent() + ) and + ( + if nEmbeds >= 1 + then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) + else e1 = MkNoIComponent() + ) and + ( + if nEmbeds >= 2 + then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) + else e2 = MkNoIComponent() + ) +} + +pragma[nomagic] +predicate unpackAndUnaliasInterfaceType( + InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, + TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, + TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, + boolean isComparable +) { + exists( + OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, + OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, + OptInterfaceComponent e2a + | + unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and + c0 = c0a.getWithDeepUnaliasedType() and + c1 = c1a.getWithDeepUnaliasedType() and + c2 = c2a.getWithDeepUnaliasedType() and + c3 = c3a.getWithDeepUnaliasedType() and + c4 = c4a.getWithDeepUnaliasedType() and + e1 = e1a.getWithDeepUnaliasedType() and + e2 = e2a.getWithDeepUnaliasedType() + ) +} + +/** An interface type. */ +class InterfaceType extends @interfacetype, CompositeType { + private Type getMethodType(int i, string name) { + i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) + } + + /** + * Holds if `tp` is a directly embedded type with index `index`. + * + * `tp` (or its underlying type) is either a type set literal type or an + * interface type. + */ + private predicate hasDirectlyEmbeddedType(int index, Type tp) { + index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) + } + + private InterfaceType getDeepUnaliasedTypeCandidate() { + exists( + OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, + OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, + OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable + | + unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, + isComparable) and + unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) + ) + } + + private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + ( + i = 5 or + this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) + ) and + exists(string name | + unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() + ) + } + + private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 2 and + ( + i = 2 or + this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) + ) and + exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | + unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) + ) + } + + override InterfaceType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | + this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) + or + nComponents <= 5 + ) and + exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | + this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) + or + nEmbeds <= 2 + ) + } +} + +pragma[nomagic] +private predicate unpackTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + nComponents = count(int i | component_types(tt, i, _, _)) and + (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and + (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and + (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) +} + +pragma[nomagic] +private predicate unpackAndUnaliasTupleType( + TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents +) { + exists(OptType c0a, OptType c1a, OptType c2a | + unpackTupleType(tt, c0a, c1a, c2a, nComponents) and + c0 = c0a.getDeepUnaliasedType() and + c1 = c1a.getDeepUnaliasedType() and + c2 = c2a.getDeepUnaliasedType() + ) +} + +/** A tuple type. */ +class TupleType extends @tupletype, CompositeType { + /** Gets the `i`th component type of this tuple type. */ + Type getComponentType(int i) { component_types(this, i, _, result) } + + private TupleType getCandidateDeepUnaliasedType() { + exists(OptType c0, OptType c1, OptType c2, int nComponents | + unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and + unpackTupleType(result, c0, c1, c2, nComponents) + ) + } + + private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { + tt = this.getCandidateDeepUnaliasedType() and + i >= 3 and + ( + i = 3 + or + this.isDeepUnaliasedTypeUpTo(tt, i - 1) + ) and + tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() + } + + override TupleType getDeepUnaliasedType() { + result = this.getCandidateDeepUnaliasedType() and + exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | + this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) + or + nComponents <= 3 + ) + } +} + +// Reasonably efficiently map from a signature type to its +// deep-unaliased equivalent, by using a single join for the leading 5 parameters +// and/or 3 results. +private newtype TOptType = + MkNoType() or + MkSomeType(Type tp) + +private class OptType extends TOptType { + OptType getDeepUnaliasedType() { + exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) + or + this = MkNoType() and result = MkNoType() + } + + string toString() { + exists(Type t | this = MkSomeType(t) | result = t.toString()) + or + this = MkNoType() and result = "no type" + } +} + +pragma[nomagic] +private predicate unpackSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + nParams = sig.getNumParameter() and + nResults = sig.getNumResult() and + (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and + (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and + (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and + (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and + (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and + (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and + (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and + (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and + (if sig.isVariadic() then isVariadic = true else isVariadic = false) +} + +pragma[nomagic] +private predicate unpackAndUnaliasSignatureType( + SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, + int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic +) { + exists( + OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, + OptType result0a, OptType result1a, OptType result2a + | + unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, + result1a, result2a, nResults, isVariadic) + | + param0 = param0a.getDeepUnaliasedType() and + param1 = param1a.getDeepUnaliasedType() and + param2 = param2a.getDeepUnaliasedType() and + param3 = param3a.getDeepUnaliasedType() and + param4 = param4a.getDeepUnaliasedType() and + result0 = result0a.getDeepUnaliasedType() and + result1 = result1a.getDeepUnaliasedType() and + result2 = result2a.getDeepUnaliasedType() + ) +} + +/** A signature type. */ +class SignatureType extends @signaturetype, CompositeType { + /** Gets the `i`th parameter type of this signature type. */ + Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } + + /** Gets the `i`th result type of this signature type. */ + Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } + + /** Gets the number of parameters specified by this signature. */ + int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } + + /** Gets the number of results specified by this signature. */ + int getNumResult() { result = count(int i | exists(this.getResultType(i))) } + + /** Holds if this signature type is variadic. */ + predicate isVariadic() { variadic(this) } + + private SignatureType getDeepUnaliasedTypeCandidate() { + exists( + OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, + OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic + | + unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, + result1, result2, nResults, isVariadic) and + unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, + result2, nResults, isVariadic) + ) + } + + // These incremental recursive implementations only apply from parameter 5 or result 3 + // upwards to avoid constructing large squares of candidates -- the initial parameters + // and results are taken care of by the candidate predicate. + private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 5 and + (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and + unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() + } + + private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { + unaliased = this.getDeepUnaliasedTypeCandidate() and + i >= 3 and + (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and + unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() + } + + override SignatureType getDeepUnaliasedType() { + result = this.getDeepUnaliasedTypeCandidate() and + exists(int nParams, int nResults | + this.getNumParameter() = nParams and this.getNumResult() = nResults + | + ( + nParams <= 5 + or + this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) + ) and + ( + nResults <= 3 + or + this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) + ) + ) + } +} + +/** A map type. */ +class MapType extends @maptype, CompositeType { + /** Gets the key type of this map type. */ + Type getKeyType() { key_type(this, result) } + + /** Gets the value type of this map type. */ + Type getValueType() { element_type(this, result) } + + override MapType getDeepUnaliasedType() { + result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and + result.getValueType() = this.getValueType().getDeepUnaliasedType() + } +} + +/** A channel type. */ +class ChanType extends @chantype, CompositeType { + /** Gets the element type of this channel type. */ + Type getElementType() { element_type(this, result) } +} + +/** A channel type that can only send. */ +class SendChanType extends @sendchantype, ChanType { + override SendChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can only receive. */ +class RecvChanType extends @recvchantype, ChanType { + override RecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A channel type that can both send and receive. */ +class SendRecvChanType extends @sendrcvchantype, ChanType { + override SendRecvChanType getDeepUnaliasedType() { + result.getElementType() = this.getElementType().getDeepUnaliasedType() + } +} + +/** A named type. */ +class NamedType extends @namedtype, CompositeType { + Type getBaseType() { underlying_type(this, result) } +} + +/** + * The predeclared `comparable` type. + */ +class ComparableType extends NamedType { + ComparableType() { typename(this, "comparable") } +} + +/** An alias type. */ +class AliasType extends @typealias, CompositeType { + /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ + Type getRhs() { alias_rhs(this, result) } + + override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } +} + +/** + * Gets the non-alias type at the end of the alias chain starting at `t`. + * + * If `t` is not an alias type then `result` is `t`. + */ +Type unalias(Type t) { + not t instanceof AliasType and result = t + or + result = unalias(t.(AliasType).getRhs()) +} + +predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } + +// END ALIASES.QLL + +class Object extends @object { + string toString() { result = "object" } +} + +class Ident extends @ident { + string toString() { result = "identifier" } +} + +// Redirect references to e.g. a struct field `x MyInt` +// onto the corresponding field `x int` of the unaliased type. +Object getReplacementField(Object o) { + exists(StructType st, StructType unaliasedSt, string name | + fieldstructs(o, st) and + unaliasedSt = st.getDeepUnaliasedType() and + objects(o, _, name) and + fieldstructs(result, unaliasedSt) and + objects(result, _, name) + ) +} + +from Ident i, Object o, Object replacementO +where + uses(i, o) and + ( + replacementO = getReplacementField(o) + or + not exists(getReplacementField(o)) and replacementO = o + ) +select i, replacementO From e547c70f748dfe3f74ebbda36a52ba594e705eed Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 19:42:36 +0100 Subject: [PATCH 30/36] Merge downgrade scripts --- .../aliases.qll | 614 ----------------- .../array_length.ql | 619 ----------------- .../base_type.ql | 619 ----------------- .../component_types.ql | 619 ----------------- .../element_type.ql | 619 ----------------- ...{defs.ql => explicit_aliases_downgrade.ql} | 112 ++- .../fieldstructs.ql | 624 ----------------- .../key_type.ql | 619 ----------------- .../objects.ql | 623 ----------------- .../objecttypes.ql | 624 ----------------- .../type_objects.ql | 627 ----------------- .../type_of.ql | 621 ----------------- .../typename.ql | 623 ----------------- .../typeparam.ql | 625 ----------------- .../types.ql | 622 ----------------- .../underlying_type.ql | 618 ----------------- .../update_lib_copies.py | 40 -- .../upgrade.properties | 34 +- .../uses.ql | 644 ------------------ .../variadic.ql | 619 ----------------- 20 files changed, 122 insertions(+), 10643 deletions(-) delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql rename go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/{defs.ql => explicit_aliases_downgrade.ql} (88%) delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql delete mode 100644 go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll deleted file mode 100644 index 2ecdedcb0f34..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/aliases.qll +++ /dev/null @@ -1,614 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql deleted file mode 100644 index 679b73fef76a..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/array_length.ql +++ /dev/null @@ -1,619 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -from ArrayType at, string length -where - array_length(at, length) and - not containsAliases(at) -select at, length diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql deleted file mode 100644 index 2d1b00ce3a60..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/base_type.ql +++ /dev/null @@ -1,619 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -from PointerType pt, Type base -where - base_type(pt, base) and - not containsAliases(pt) -select pt, base diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql deleted file mode 100644 index d828bc6cd259..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/component_types.ql +++ /dev/null @@ -1,619 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -from CompositeType ct, int i, string name, Type tp -where - component_types(ct, i, name, tp) and - not containsAliases(ct) -select ct, i, name, tp diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql deleted file mode 100644 index 34270bbcd82a..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/element_type.ql +++ /dev/null @@ -1,619 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -from CompositeType ct, Type et -where - element_type(ct, et) and - not containsAliases(ct) -select ct, et diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/defs.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/explicit_aliases_downgrade.ql similarity index 88% rename from go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/defs.ql rename to go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/explicit_aliases_downgrade.ql index 5fa8e35720e4..363327f81ba3 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/defs.ql +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/explicit_aliases_downgrade.ql @@ -611,8 +611,6 @@ Type unalias(Type t) { predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } -// END ALIASES.QLL - class Object extends @object { string toString() { result = "object" } } @@ -621,6 +619,18 @@ class Ident extends @ident { string toString() { result = "identifier" } } +class Expr extends @expr { + string toString() { result = "expr" } +} + +class TypeParamType extends @typeparamtype { + string toString() { result = "type parameter" } +} + +class TypeParamParentObject extends @typeparamparentobject { + string toString() { result = "type parameter parent object" } +} + // Redirect references to e.g. a struct field `x MyInt` // onto the corresponding field `x int` of the unaliased type. Object getReplacementField(Object o) { @@ -633,12 +643,100 @@ Object getReplacementField(Object o) { ) } -from Ident i, Object o, Object replacementO -where - defs(i, o) and - ( +query predicate new_array_length(ArrayType at, string length) { + array_length(at, length) and + not containsAliases(at) +} + +query predicate new_base_type(PointerType pt, Type base) { + base_type(pt, base) and + not containsAliases(pt) +} + +query predicate new_component_types(CompositeType ct, int i, string name, Type tp) { + component_types(ct, i, name, tp) and + not containsAliases(ct) +} + +query predicate new_defs(Ident i, Object replacementO) { + exists(Object o | defs(i, o) | + replacementO = getReplacementField(o) + or + not exists(getReplacementField(o)) and replacementO = o + ) +} + +query predicate new_element_type(CompositeType ct, Type et) { + element_type(ct, et) and + not containsAliases(ct) +} + +query predicate new_fieldstructs(Object field, StructType st) { + fieldstructs(field, st) and + not containsAliases(st) +} + +query predicate new_key_type(MapType mt, Type kt) { + key_type(mt, kt) and + not containsAliases(mt) +} + +query predicate new_objects(Object o, int kind, string name) { + objects(o, kind, name) and + not exists(StructType st | fieldstructs(o, st) and containsAliases(st)) +} + +query predicate new_objecttypes(Object o, Type newT) { + exists(Type t | + objecttypes(o, t) and + not exists(StructType st | fieldstructs(o, st) and containsAliases(st)) + | + // Note this means that type alises really do have an object in the new database; + // they just have types that resolve to the target of the alias, not the alias itself. + newT = t.getDeepUnaliasedType() + ) +} + +query predicate new_type_objects(Type type, Object object) { + type_objects(type, object) and + not containsAliases(type) +} + +query predicate new_type_of(Expr e, Type newT) { + exists(Type t | type_of(e, t) | newT = t.getDeepUnaliasedType()) +} + +query predicate new_typename(Type type, string name) { + typename(type, name) and + not containsAliases(type) +} + +query predicate new_typeparam( + TypeParamType tp, string name, CompositeType newBound, TypeParamParentObject parent, int idx +) { + exists(Type bound | typeparam(tp, name, bound, parent, idx) | + newBound = bound.getDeepUnaliasedType() + ) +} + +query predicate new_types(Type t, int kind) { + types(t, kind) and + not containsAliases(t) +} + +query predicate new_underlying_type(NamedType nt, Type newUnderlyingType) { + exists(Type ut | underlying_type(nt, ut) | newUnderlyingType = ut.getDeepUnaliasedType()) +} + +query predicate new_uses(Ident i, Object replacementO) { + exists(Object o | uses(i, o) | replacementO = getReplacementField(o) or not exists(getReplacementField(o)) and replacementO = o ) -select i, replacementO +} + +query predicate new_variadic(Type t) { + variadic(t) and + not containsAliases(t) +} \ No newline at end of file diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql deleted file mode 100644 index c9e133de2612..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/fieldstructs.ql +++ /dev/null @@ -1,624 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL - -class Object extends @object { - string toString() { result = "object" } -} - -from Object field, StructType st -where - fieldstructs(field, st) and - not containsAliases(st) -select field, st diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql deleted file mode 100644 index 61e79dddbd67..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/key_type.ql +++ /dev/null @@ -1,619 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -from MapType mt, Type kt -where - key_type(mt, kt) and - not containsAliases(mt) -select mt, kt diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql deleted file mode 100644 index 1513eaf2aa4e..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objects.ql +++ /dev/null @@ -1,623 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -class Object extends @object { - string toString() { result = "object" } -} - -from Object o, int kind, string name -where - objects(o, kind, name) and - not exists(StructType st | fieldstructs(o, st) and containsAliases(st)) -select o, kind, name diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql deleted file mode 100644 index 889414881876..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/objecttypes.ql +++ /dev/null @@ -1,624 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -class Object extends @object { - string toString() { result = "object" } -} - -from Object o, Type t -where objecttypes(o, t) -and not exists(StructType st | fieldstructs(o, st) and containsAliases(st)) -// Note this means that type alises really do have an object in the new database; -// they just have types that resolve to the target of the alias, not the alias itself. -select o, t.getDeepUnaliasedType() diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql deleted file mode 100644 index 01c31c974033..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_objects.ql +++ /dev/null @@ -1,627 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -class Object extends @object { - string toString() { result = "object" } -} - -// The schema for types and typename are: -// -// types(unique int id: @type, int kind: int ref); -// type_objects(unique int tp: @type ref, int object: @object ref); -from Type type, Object object -where - type_objects(type, object) and - not containsAliases(type) -select type, object diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql deleted file mode 100644 index 20b86949f47e..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/type_of.ql +++ /dev/null @@ -1,621 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -class Expr extends @expr { - string toString() { result = "expr" } -} - -from Expr e, Type t -where type_of(e, t) -select e, t.getDeepUnaliasedType() diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql deleted file mode 100644 index 8f9dc9bb5d90..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typename.ql +++ /dev/null @@ -1,623 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -// The schema for types and typename are: -// -// types(unique int id: @type, int kind: int ref); -// typename(unique int tp: @type ref, string name: string ref); -from Type type, string name -where - typename(type, name) and - not containsAliases(type) -select type, name diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql deleted file mode 100644 index 667de3090f4f..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/typeparam.ql +++ /dev/null @@ -1,625 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -class TypeParamType extends @typeparamtype { - string toString() { result = "type parameter" } -} - -class TypeParamParentObject extends @typeparamparentobject { - string toString() { result = "type parameter parent object" } -} - -from TypeParamType tp, string name, CompositeType bound, TypeParamParentObject parent, int idx -where typeparam(tp, name, bound, parent, idx) -select tp, name, bound.getDeepUnaliasedType(), parent, idx diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql deleted file mode 100644 index 77a0850b4a9c..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/types.ql +++ /dev/null @@ -1,622 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -// The schema for types is: -// -// types(unique int id: @type, int kind: int ref); -from Type type, int kind -where - types(type, kind) and - not containsAliases(type) -select type, kind diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql deleted file mode 100644 index 3def6be60be9..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/underlying_type.ql +++ /dev/null @@ -1,618 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL - -from NamedType nt, Type ut -where underlying_type(nt, ut) -select nt, ut.getDeepUnaliasedType() diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py deleted file mode 100644 index f9306b1c40aa..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/update_lib_copies.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -import glob - -thisdir = os.path.dirname(os.path.realpath(__file__)) - -toupdate = dict() - -startstr = "// BEGIN ALIASES.QLL" -endstr = "// END ALIASES.QLL" - -somelibcontentf = None -somelibcontent = None - -for f in glob.glob(os.path.join(thisdir, "*.ql")): - with open(f, "r") as fp: - content = fp.read() - idx = content.index(startstr) - if idx != 0 and idx != -1: - raise Exception("Expected file %s that contains aliases.qll to start with it (found it at offset %d)" % (f, idx)) - if idx == 0: - endidx = content.index(endstr) - if endidx == -1: - raise Exception("Expected file %s that contains aliases.qll to contain the end-of-library token %s" % (f, endstr)) - libcontent = content[idx : endidx + len(endstr)] - toupdate[f] = (content, libcontent) - somelibcontentf = f - somelibcontent = libcontent - -for (f, (content, libcontent)) in toupdate.items(): - if libcontent != somelibcontent: - raise Exception("Files that include aliases.qll disagree about its content (e.g., files %s and %s)" % (somelibcontentf, f)) - -print("Updating %d files that include aliases.qll" % len(toupdate)) - -with open(os.path.join(thisdir, "aliases.qll"), "r") as fp: - newlibcontent = fp.read().strip() - -for (f, (content, _)) in toupdate.items(): - with open(f, "w") as fp: - fp.write(newlibcontent + content[len(somelibcontent):]) diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties index 1a36d02c5e49..d3367c26da34 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties @@ -2,22 +2,22 @@ description: Remove support for type aliases compatibility: full alias_rhs.rel: delete -array_length.rel: run array_length.qlo -base_type.rel: run base_type.qlo +array_length.rel: run explicit_aliases_downgrade.qlo new_array_length +base_type.rel: run explicit_aliases_downgrade.qlo new_base_type component_tags.rel: delete -component_types.rel: run component_types.qlo -defs.rel: run defs.qlo -element_type.rel: run element_type.qlo -fieldstructs.rel: run fieldstructs.qlo +component_types.rel: run explicit_aliases_downgrade.qlo new_component_types +defs.rel: run explicit_aliases_downgrade.qlo new_defs +element_type.rel: run explicit_aliases_downgrade.qlo new_element_type +fieldstructs.rel: run explicit_aliases_downgrade.qlo new_fieldstructs interface_private_method_ids: delete -key_type.rel: run key_type.qlo -objects.rel: run objects.qlo -objecttypes.rel: run objecttypes.qlo -type_objects.rel: run type_objects.qlo -type_of.rel: run type_of.qlo -typename.rel: run typename.qlo -typeparam.rel: run typeparam.qlo -types.rel: run types.qlo -underlying_type.rel: run underlying_type.qlo -uses.rel: run uses.qlo -variadic.rel: run variadic.qlo +key_type.rel: run explicit_aliases_downgrade.qlo new_key_type +objects.rel: run explicit_aliases_downgrade.qlo new_objects +objecttypes.rel: run explicit_aliases_downgrade.qlo new_objecttypes +type_objects.rel: run explicit_aliases_downgrade.qlo new_type_objects +type_of.rel: run explicit_aliases_downgrade.qlo new_type_of +typename.rel: run explicit_aliases_downgrade.qlo new_typename +typeparam.rel: run explicit_aliases_downgrade.qlo new_typeparam +types.rel: run explicit_aliases_downgrade.qlo new_types +underlying_type.rel: run explicit_aliases_downgrade.qlo new_underlying_type +uses.rel: run explicit_aliases_downgrade.qlo new_uses +variadic.rel: run explicit_aliases_downgrade.qlo new_variadic diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql deleted file mode 100644 index 0b40e2253a32..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/uses.ql +++ /dev/null @@ -1,644 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL - -class Object extends @object { - string toString() { result = "object" } -} - -class Ident extends @ident { - string toString() { result = "identifier" } -} - -// Redirect references to e.g. a struct field `x MyInt` -// onto the corresponding field `x int` of the unaliased type. -Object getReplacementField(Object o) { - exists(StructType st, StructType unaliasedSt, string name | - fieldstructs(o, st) and - unaliasedSt = st.getDeepUnaliasedType() and - objects(o, _, name) and - fieldstructs(result, unaliasedSt) and - objects(result, _, name) - ) -} - -from Ident i, Object o, Object replacementO -where - uses(i, o) and - ( - replacementO = getReplacementField(o) - or - not exists(getReplacementField(o)) and replacementO = o - ) -select i, replacementO diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql deleted file mode 100644 index 9d06a63ab1aa..000000000000 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/variadic.ql +++ /dev/null @@ -1,619 +0,0 @@ -// BEGIN ALIASES.QLL -// Database scripts can't import, but this is the definitive copy of the support routines for mapping types to their unaliased equivalent. Ensure this code is in sync between aliases.qll and all copies in individual table .ql files. -/** A Go type. */ -class Type extends @type { - /** - * Gets this type with all aliases substituted for their underlying type. - * - * Note named types are not substituted. - */ - Type getDeepUnaliasedType() { result = this } - - /** - * Gets a basic textual representation of this type. - */ - string toString() { result = "type" } -} - -/** A composite type, that is, not a basic type. */ -class CompositeType extends @compositetype, Type { } - -/** An array type. */ -class ArrayType extends @arraytype, CompositeType { - /** Gets the element type of this array type. */ - Type getElementType() { element_type(this, result) } - - /** Gets the length of this array type as a string. */ - string getLengthString() { array_length(this, result) } - - override ArrayType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() and - result.getLengthString() = this.getLengthString() - } -} - -/** A slice type. */ -class SliceType extends @slicetype, CompositeType { - /** Gets the element type of this slice type. */ - Type getElementType() { element_type(this, result) } - - override SliceType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -// Improve efficiency of matching a struct to its unaliased equivalent -// by unpacking the first 5 fields and tags, allowing a single join -// to strongly constrain the available candidates. -private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) { - component_types(s, i, name, tp) and component_tags(s, i, tag) -} - -private newtype TOptStructComponent = - MkNoComponent() or - MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) } - -private class OptStructComponent extends TOptStructComponent { - OptStructComponent getWithDeepUnaliasedType() { - this = MkNoComponent() and result = MkNoComponent() - or - exists(string name, Type tp, string tag | - this = MkSomeComponent(name, tp, tag) and - result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag) - ) - } - - string toString() { result = "struct component" } -} - -private class StructComponent extends MkSomeComponent { - string toString() { result = "struct component" } - - predicate isComponentOf(StructType s, int i) { - exists(string name, Type tp, string tag | - hasComponentTypeAndTag(s, i, name, tp, tag) and - this = MkSomeComponent(name, tp, tag) - ) - } -} - -pragma[nomagic] -predicate unpackStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - nComponents = count(int i | component_types(s, i, _, _)) and - ( - if nComponents >= 1 - then c0 = any(StructComponent sc | sc.isComponentOf(s, 0)) - else c0 = MkNoComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(StructComponent sc | sc.isComponentOf(s, 1)) - else c1 = MkNoComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(StructComponent sc | sc.isComponentOf(s, 2)) - else c2 = MkNoComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(StructComponent sc | sc.isComponentOf(s, 3)) - else c3 = MkNoComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(StructComponent sc | sc.isComponentOf(s, 4)) - else c4 = MkNoComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasStructType( - StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2, - TOptStructComponent c3, TOptStructComponent c4, int nComponents -) { - exists( - OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a, - OptStructComponent c4a - | - unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() - ) -} - -/** A struct type. */ -class StructType extends @structtype, CompositeType { - private StructType getDeepUnaliasedTypeCandidate() { - exists( - OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3, - OptStructComponent c4, int nComponents - | - unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and - unpackStructType(result, c0, c1, c2, c3, c4, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) { - // Note we must use component_types not hasOwnField here because component_types may specify - // interface-in-struct embedding, but hasOwnField does not return such members. - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.isDeepUnaliasedTypeUpTo(unaliased, i - 1) - ) and - exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) | - hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag) - ) - } - - override StructType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) - } -} - -/** A pointer type. */ -class PointerType extends @pointertype, CompositeType { - /** Gets the base type of this pointer type. */ - Type getBaseType() { base_type(this, result) } - - override PointerType getDeepUnaliasedType() { - result.getBaseType() = this.getBaseType().getDeepUnaliasedType() - } -} - -private predicate isInterfaceComponentWithQualifiedName( - InterfaceType intf, int idx, string qualifiedName, Type tp -) { - exists(string name | component_types(intf, idx, name, tp) | - interface_private_method_ids(intf, idx, qualifiedName) - or - not interface_private_method_ids(intf, idx, _) and qualifiedName = name - ) -} - -private newtype TOptInterfaceComponent = - MkNoIComponent() or - MkSomeIComponent(string name, Type tp) { - isInterfaceComponentWithQualifiedName(any(InterfaceType i), _, name, tp) - } - -private class OptInterfaceComponent extends TOptInterfaceComponent { - OptInterfaceComponent getWithDeepUnaliasedType() { - this = MkNoIComponent() and result = MkNoIComponent() - or - exists(string name, Type tp | - this = MkSomeIComponent(name, tp) and - result = MkSomeIComponent(name, tp.getDeepUnaliasedType()) - ) - } - - string toString() { result = "interface component" } -} - -private class InterfaceComponent extends MkSomeIComponent { - string toString() { result = "interface component" } - - predicate isComponentOf(InterfaceType intf, int i) { - exists(string name, Type tp | - isInterfaceComponentWithQualifiedName(intf, i, name, tp) and - this = MkSomeIComponent(name, tp) - ) - } -} - -pragma[nomagic] -predicate unpackInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - nComponents = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i >= 0) and - nEmbeds = count(int i | isInterfaceComponentWithQualifiedName(intf, i, _, _) and i < 0) and - ( - if intf = any(ComparableType comparable).getBaseType() - then isComparable = true - else isComparable = false - ) and - ( - if nComponents >= 1 - then c0 = any(InterfaceComponent ic | ic.isComponentOf(intf, 0)) - else c0 = MkNoIComponent() - ) and - ( - if nComponents >= 2 - then c1 = any(InterfaceComponent ic | ic.isComponentOf(intf, 1)) - else c1 = MkNoIComponent() - ) and - ( - if nComponents >= 3 - then c2 = any(InterfaceComponent ic | ic.isComponentOf(intf, 2)) - else c2 = MkNoIComponent() - ) and - ( - if nComponents >= 4 - then c3 = any(InterfaceComponent ic | ic.isComponentOf(intf, 3)) - else c3 = MkNoIComponent() - ) and - ( - if nComponents >= 5 - then c4 = any(InterfaceComponent ic | ic.isComponentOf(intf, 4)) - else c4 = MkNoIComponent() - ) and - ( - if nEmbeds >= 1 - then e1 = any(InterfaceComponent ic | ic.isComponentOf(intf, -1)) - else e1 = MkNoIComponent() - ) and - ( - if nEmbeds >= 2 - then e2 = any(InterfaceComponent ic | ic.isComponentOf(intf, -2)) - else e2 = MkNoIComponent() - ) -} - -pragma[nomagic] -predicate unpackAndUnaliasInterfaceType( - InterfaceType intf, TOptInterfaceComponent c0, TOptInterfaceComponent c1, - TOptInterfaceComponent c2, TOptInterfaceComponent c3, TOptInterfaceComponent c4, - TOptInterfaceComponent e1, TOptInterfaceComponent e2, int nComponents, int nEmbeds, - boolean isComparable -) { - exists( - OptInterfaceComponent c0a, OptInterfaceComponent c1a, OptInterfaceComponent c2a, - OptInterfaceComponent c3a, OptInterfaceComponent c4a, OptInterfaceComponent e1a, - OptInterfaceComponent e2a - | - unpackInterfaceType(intf, c0a, c1a, c2a, c3a, c4a, e1a, e2a, nComponents, nEmbeds, isComparable) and - c0 = c0a.getWithDeepUnaliasedType() and - c1 = c1a.getWithDeepUnaliasedType() and - c2 = c2a.getWithDeepUnaliasedType() and - c3 = c3a.getWithDeepUnaliasedType() and - c4 = c4a.getWithDeepUnaliasedType() and - e1 = e1a.getWithDeepUnaliasedType() and - e2 = e2a.getWithDeepUnaliasedType() - ) -} - -/** An interface type. */ -class InterfaceType extends @interfacetype, CompositeType { - private Type getMethodType(int i, string name) { - i >= 0 and isInterfaceComponentWithQualifiedName(this, i, name, result) - } - - /** - * Holds if `tp` is a directly embedded type with index `index`. - * - * `tp` (or its underlying type) is either a type set literal type or an - * interface type. - */ - private predicate hasDirectlyEmbeddedType(int index, Type tp) { - index >= 0 and isInterfaceComponentWithQualifiedName(this, -(index + 1), _, tp) - } - - private InterfaceType getDeepUnaliasedTypeCandidate() { - exists( - OptInterfaceComponent c0, OptInterfaceComponent c1, OptInterfaceComponent c2, - OptInterfaceComponent c3, OptInterfaceComponent c4, OptInterfaceComponent e1, - OptInterfaceComponent e2, int nComponents, int nEmbeds, boolean isComparable - | - unpackAndUnaliasInterfaceType(this, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, - isComparable) and - unpackInterfaceType(result, c0, c1, c2, c3, c4, e1, e2, nComponents, nEmbeds, isComparable) - ) - } - - private predicate hasDeepUnaliasedComponentTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - ( - i = 5 or - this.hasDeepUnaliasedComponentTypesUpTo(unaliased, i - 1) - ) and - exists(string name | - unaliased.getMethodType(i, name) = this.getMethodType(i, name).getDeepUnaliasedType() - ) - } - - private predicate hasDeepUnaliasedEmbeddedTypesUpTo(InterfaceType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 2 and - ( - i = 2 or - this.hasDeepUnaliasedEmbeddedTypesUpTo(unaliased, i - 1) - ) and - exists(Type tp | this.hasDirectlyEmbeddedType(i, tp) | - unaliased.hasDirectlyEmbeddedType(i, tp.getDeepUnaliasedType()) - ) - } - - override InterfaceType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nComponents | nComponents = count(int i | exists(this.getMethodType(i, _))) | - this.hasDeepUnaliasedComponentTypesUpTo(result, nComponents - 1) - or - nComponents <= 5 - ) and - exists(int nEmbeds | nEmbeds = count(int i | this.hasDirectlyEmbeddedType(i, _)) | - this.hasDeepUnaliasedEmbeddedTypesUpTo(result, nEmbeds - 1) - or - nEmbeds <= 2 - ) - } -} - -pragma[nomagic] -private predicate unpackTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - nComponents = count(int i | component_types(tt, i, _, _)) and - (if nComponents >= 1 then c0 = MkSomeType(tt.getComponentType(0)) else c0 = MkNoType()) and - (if nComponents >= 2 then c1 = MkSomeType(tt.getComponentType(1)) else c1 = MkNoType()) and - (if nComponents >= 3 then c2 = MkSomeType(tt.getComponentType(2)) else c2 = MkNoType()) -} - -pragma[nomagic] -private predicate unpackAndUnaliasTupleType( - TupleType tt, TOptType c0, TOptType c1, TOptType c2, int nComponents -) { - exists(OptType c0a, OptType c1a, OptType c2a | - unpackTupleType(tt, c0a, c1a, c2a, nComponents) and - c0 = c0a.getDeepUnaliasedType() and - c1 = c1a.getDeepUnaliasedType() and - c2 = c2a.getDeepUnaliasedType() - ) -} - -/** A tuple type. */ -class TupleType extends @tupletype, CompositeType { - /** Gets the `i`th component type of this tuple type. */ - Type getComponentType(int i) { component_types(this, i, _, result) } - - private TupleType getCandidateDeepUnaliasedType() { - exists(OptType c0, OptType c1, OptType c2, int nComponents | - unpackAndUnaliasTupleType(this, c0, c1, c2, nComponents) and - unpackTupleType(result, c0, c1, c2, nComponents) - ) - } - - private predicate isDeepUnaliasedTypeUpTo(TupleType tt, int i) { - tt = this.getCandidateDeepUnaliasedType() and - i >= 3 and - ( - i = 3 - or - this.isDeepUnaliasedTypeUpTo(tt, i - 1) - ) and - tt.getComponentType(i) = this.getComponentType(i).getDeepUnaliasedType() - } - - override TupleType getDeepUnaliasedType() { - result = this.getCandidateDeepUnaliasedType() and - exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) | - this.isDeepUnaliasedTypeUpTo(result, nComponents - 1) - or - nComponents <= 3 - ) - } -} - -// Reasonably efficiently map from a signature type to its -// deep-unaliased equivalent, by using a single join for the leading 5 parameters -// and/or 3 results. -private newtype TOptType = - MkNoType() or - MkSomeType(Type tp) - -private class OptType extends TOptType { - OptType getDeepUnaliasedType() { - exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType())) - or - this = MkNoType() and result = MkNoType() - } - - string toString() { - exists(Type t | this = MkSomeType(t) | result = t.toString()) - or - this = MkNoType() and result = "no type" - } -} - -pragma[nomagic] -private predicate unpackSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - nParams = sig.getNumParameter() and - nResults = sig.getNumResult() and - (if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and - (if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and - (if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and - (if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and - (if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and - (if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and - (if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and - (if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and - (if sig.isVariadic() then isVariadic = true else isVariadic = false) -} - -pragma[nomagic] -private predicate unpackAndUnaliasSignatureType( - SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, - int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic -) { - exists( - OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a, - OptType result0a, OptType result1a, OptType result2a - | - unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a, - result1a, result2a, nResults, isVariadic) - | - param0 = param0a.getDeepUnaliasedType() and - param1 = param1a.getDeepUnaliasedType() and - param2 = param2a.getDeepUnaliasedType() and - param3 = param3a.getDeepUnaliasedType() and - param4 = param4a.getDeepUnaliasedType() and - result0 = result0a.getDeepUnaliasedType() and - result1 = result1a.getDeepUnaliasedType() and - result2 = result2a.getDeepUnaliasedType() - ) -} - -/** A signature type. */ -class SignatureType extends @signaturetype, CompositeType { - /** Gets the `i`th parameter type of this signature type. */ - Type getParameterType(int i) { i >= 0 and component_types(this, i + 1, _, result) } - - /** Gets the `i`th result type of this signature type. */ - Type getResultType(int i) { i >= 0 and component_types(this, -(i + 1), _, result) } - - /** Gets the number of parameters specified by this signature. */ - int getNumParameter() { result = count(int i | exists(this.getParameterType(i))) } - - /** Gets the number of results specified by this signature. */ - int getNumResult() { result = count(int i | exists(this.getResultType(i))) } - - /** Holds if this signature type is variadic. */ - predicate isVariadic() { variadic(this) } - - private SignatureType getDeepUnaliasedTypeCandidate() { - exists( - OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams, - OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic - | - unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0, - result1, result2, nResults, isVariadic) and - unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1, - result2, nResults, isVariadic) - ) - } - - // These incremental recursive implementations only apply from parameter 5 or result 3 - // upwards to avoid constructing large squares of candidates -- the initial parameters - // and results are taken care of by the candidate predicate. - private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 5 and - (i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and - unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType() - } - - private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) { - unaliased = this.getDeepUnaliasedTypeCandidate() and - i >= 3 and - (i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and - unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType() - } - - override SignatureType getDeepUnaliasedType() { - result = this.getDeepUnaliasedTypeCandidate() and - exists(int nParams, int nResults | - this.getNumParameter() = nParams and this.getNumResult() = nResults - | - ( - nParams <= 5 - or - this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) - ) and - ( - nResults <= 3 - or - this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1) - ) - ) - } -} - -/** A map type. */ -class MapType extends @maptype, CompositeType { - /** Gets the key type of this map type. */ - Type getKeyType() { key_type(this, result) } - - /** Gets the value type of this map type. */ - Type getValueType() { element_type(this, result) } - - override MapType getDeepUnaliasedType() { - result.getKeyType() = this.getKeyType().getDeepUnaliasedType() and - result.getValueType() = this.getValueType().getDeepUnaliasedType() - } -} - -/** A channel type. */ -class ChanType extends @chantype, CompositeType { - /** Gets the element type of this channel type. */ - Type getElementType() { element_type(this, result) } -} - -/** A channel type that can only send. */ -class SendChanType extends @sendchantype, ChanType { - override SendChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can only receive. */ -class RecvChanType extends @recvchantype, ChanType { - override RecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A channel type that can both send and receive. */ -class SendRecvChanType extends @sendrcvchantype, ChanType { - override SendRecvChanType getDeepUnaliasedType() { - result.getElementType() = this.getElementType().getDeepUnaliasedType() - } -} - -/** A named type. */ -class NamedType extends @namedtype, CompositeType { - Type getBaseType() { underlying_type(this, result) } -} - -/** - * The predeclared `comparable` type. - */ -class ComparableType extends NamedType { - ComparableType() { typename(this, "comparable") } -} - -/** An alias type. */ -class AliasType extends @typealias, CompositeType { - /** Gets the aliased type (i.e. that appears on the RHS of the alias definition). */ - Type getRhs() { alias_rhs(this, result) } - - override Type getDeepUnaliasedType() { result = unalias(this).getDeepUnaliasedType() } -} - -/** - * Gets the non-alias type at the end of the alias chain starting at `t`. - * - * If `t` is not an alias type then `result` is `t`. - */ -Type unalias(Type t) { - not t instanceof AliasType and result = t - or - result = unalias(t.(AliasType).getRhs()) -} - -predicate containsAliases(Type t) { t != t.getDeepUnaliasedType() } - -// END ALIASES.QLL -from Type t -where - variadic(t) and - not containsAliases(t) -select t From 4fe137996b38a9781e96bef1e4d80d77a7284f78 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 20:00:45 +0100 Subject: [PATCH 31/36] Update upgrade dbscheme --- .../a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme | 3 +++ 1 file changed, 3 insertions(+) diff --git a/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme index 40dfd9635451..629b145fac46 100644 --- a/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme +++ b/go/ql/lib/upgrades/a58b81b1b4c4cccc8ca11731c1db86622f33af57/go.dbscheme @@ -212,6 +212,9 @@ component_types(int parent: @compositetype ref, int index: int ref, string name: #keyset[parent, index] component_tags(int parent: @compositetype ref, int index: int ref, string tag: string ref); +#keyset[interface, index] +interface_private_method_ids(int interface: @interfacetype ref, int index: int ref, string id: string ref); + array_length(unique int tp: @arraytype ref, string len: string ref); type_objects(unique int tp: @type ref, int object: @object ref); From c813e6627af1538dc31f312d4f1e91ad398956a0 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 21:59:53 +0100 Subject: [PATCH 32/36] Improve pretty-printer --- go/ql/lib/semmle/go/Types.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index a13be5d63ad3..e98fbc3284dd 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -1395,11 +1395,11 @@ class SignatureType extends @signaturetype, CompositeType { language[monotonicAggregates] override string pp() { - exists(string suffix | (if this.isVariadic() then suffix = "[variadic]" else suffix = "") | + exists(string suffix | (if this.isVariadic() then suffix = " [variadic]" else suffix = "") | result = "func(" + concat(int i, Type tp | tp = this.getParameterType(i) | tp.pp(), ", " order by i) + ") " + concat(int i, Type tp | tp = this.getResultType(i) | tp.pp(), ", " order by i) + - " " + suffix + suffix ) } From a56c95e1d97985748c478c2a69ba862f9c7b34e3 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 22:01:10 +0100 Subject: [PATCH 33/36] Fix downgrade deletion --- .../629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties index d3367c26da34..f60f4efc0791 100644 --- a/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties +++ b/go/downgrades/629b145fac466483e5eb38e1fd752f82cbb89196/upgrade.properties @@ -9,7 +9,7 @@ component_types.rel: run explicit_aliases_downgrade.qlo new_component_types defs.rel: run explicit_aliases_downgrade.qlo new_defs element_type.rel: run explicit_aliases_downgrade.qlo new_element_type fieldstructs.rel: run explicit_aliases_downgrade.qlo new_fieldstructs -interface_private_method_ids: delete +interface_private_method_ids.rel: delete key_type.rel: run explicit_aliases_downgrade.qlo new_key_type objects.rel: run explicit_aliases_downgrade.qlo new_objects objecttypes.rel: run explicit_aliases_downgrade.qlo new_objecttypes From 5ca026314a0bbf045cd2000b1a7cf23b55382637 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 22:02:31 +0100 Subject: [PATCH 34/36] autoformat --- go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index 8120044c9c46..dd0155ca77b1 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -158,7 +158,8 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { ) or node1 = node2.(AddressOperationNode).getOperand() and - c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType().getDeepUnaliasedType()) + c = + any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType().getDeepUnaliasedType()) or FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c, node2.(FlowSummaryNode).getSummaryNode()) From 0b3e0fb3f26dcec20599718d6e870919f325bc9b Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 2 Sep 2024 22:41:50 +0100 Subject: [PATCH 35/36] Update test expectation (now signature types pretty-print indicating if they are variadic) --- .../semmle/go/PrintAst/PrintAst.expected | 40 +++++++++---------- .../PrintAst/PrintAstExcludeComments.expected | 40 +++++++++---------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected index 4c9b7da6fe55..b8e9b00d78f9 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected @@ -53,10 +53,10 @@ input.go: # 20| 0: [CallExpr] call to Println # 20| Type = (int, error) # 20| 0: [FunctionName, SelectorExpr] selection of Println -# 20| Type = func([]any) int, error +# 20| Type = func([]any) int, error [variadic] # 20| 0: [Ident, PackageName] fmt # 20| 1: [FunctionName, Ident] Println -# 20| Type = func([]any) int, error +# 20| Type = func([]any) int, error [variadic] # 20| 1: [StringLit] "Hi" # 20| Type = string # 20| Value = [StringLit] Hi @@ -203,10 +203,10 @@ input.go: # 52| 0: [CallExpr] call to Println # 52| Type = (int, error) # 52| 0: [FunctionName, SelectorExpr] selection of Println -# 52| Type = func([]any) int, error +# 52| Type = func([]any) int, error [variadic] # 52| 0: [Ident, PackageName] fmt # 52| 1: [FunctionName, Ident] Println -# 52| Type = func([]any) int, error +# 52| Type = func([]any) int, error [variadic] # 52| 1: [StringLit] "Heard from ch1" # 52| Type = string # 52| Value = [StringLit] Heard from ch1 @@ -229,20 +229,20 @@ input.go: # 54| 0: [CallExpr] call to Println # 54| Type = (int, error) # 54| 0: [FunctionName, SelectorExpr] selection of Println -# 54| Type = func([]any) int, error +# 54| Type = func([]any) int, error [variadic] # 54| 0: [Ident, PackageName] fmt # 54| 1: [FunctionName, Ident] Println -# 54| Type = func([]any) int, error +# 54| Type = func([]any) int, error [variadic] # 54| 1: [Ident, VariableName] a # 54| Type = [1]float32 # 55| 2: [ExprStmt] expression statement # 55| 0: [CallExpr] call to Println # 55| Type = (int, error) # 55| 0: [FunctionName, SelectorExpr] selection of Println -# 55| Type = func([]any) int, error +# 55| Type = func([]any) int, error [variadic] # 55| 0: [Ident, PackageName] fmt # 55| 1: [FunctionName, Ident] Println -# 55| Type = func([]any) int, error +# 55| Type = func([]any) int, error [variadic] # 55| 1: [Ident, VariableName] w # 55| Type = bool # 56| 2: [CommClause] comm clause @@ -250,10 +250,10 @@ input.go: # 57| 0: [CallExpr] call to Println # 57| Type = (int, error) # 57| 0: [FunctionName, SelectorExpr] selection of Println -# 57| Type = func([]any) int, error +# 57| Type = func([]any) int, error [variadic] # 57| 0: [Ident, PackageName] fmt # 57| 1: [FunctionName, Ident] Println -# 57| Type = func([]any) int, error +# 57| Type = func([]any) int, error [variadic] # 58| 3: [CommClause] comm clause # 58| 0: [SendStmt] send statement # 58| 0: [Ident, VariableName] ch1 @@ -297,10 +297,10 @@ input.go: # 67| 0: [CallExpr] call to Println # 67| Type = (int, error) # 67| 0: [FunctionName, SelectorExpr] selection of Println -# 67| Type = func([]any) int, error +# 67| Type = func([]any) int, error [variadic] # 67| 0: [Ident, PackageName] fmt # 67| 1: [FunctionName, Ident] Println -# 67| Type = func([]any) int, error +# 67| Type = func([]any) int, error [variadic] # 67| 1: [Ident, VariableName] x # 67| Type = int # 68| 2: [BlockStmt] block statement @@ -316,10 +316,10 @@ input.go: # 69| 0: [CallExpr] call to Println # 69| Type = (int, error) # 69| 0: [FunctionName, SelectorExpr] selection of Println -# 69| Type = func([]any) int, error +# 69| Type = func([]any) int, error [variadic] # 69| 0: [Ident, PackageName] fmt # 69| 1: [FunctionName, Ident] Println -# 69| Type = func([]any) int, error +# 69| Type = func([]any) int, error [variadic] # 69| 1: [MinusExpr] -... # 69| Type = int # 69| 0: [Ident, VariableName] x @@ -474,10 +474,10 @@ input.go: # 115| 0: [CallExpr] call to Println # 115| Type = (int, error) # 115| 0: [FunctionName, SelectorExpr] selection of Println -# 115| Type = func([]any) int, error +# 115| Type = func([]any) int, error [variadic] # 115| 0: [Ident, PackageName] fmt # 115| 1: [FunctionName, Ident] Println -# 115| Type = func([]any) int, error +# 115| Type = func([]any) int, error [variadic] # 115| 1: [Ident, VariableName] y # 115| Type = interface { } # 116| 1: [CaseClause] case clause @@ -566,10 +566,10 @@ input.go: # 138| 0: [CallExpr] call to Print # 138| Type = (int, error) # 138| 0: [FunctionName, SelectorExpr] selection of Print -# 138| Type = func([]any) int, error +# 138| Type = func([]any) int, error [variadic] # 138| 0: [Ident, PackageName] fmt # 138| 1: [FunctionName, Ident] Print -# 138| Type = func([]any) int, error +# 138| Type = func([]any) int, error [variadic] # 138| 1: [Ident, VariableName] x # 138| Type = int # 141| 1: [RangeStmt] range statement @@ -584,10 +584,10 @@ input.go: # 142| 0: [CallExpr] call to Print # 142| Type = (int, error) # 142| 0: [FunctionName, SelectorExpr] selection of Print -# 142| Type = func([]any) int, error +# 142| Type = func([]any) int, error [variadic] # 142| 0: [Ident, PackageName] fmt # 142| 1: [FunctionName, Ident] Print -# 142| Type = func([]any) int, error +# 142| Type = func([]any) int, error [variadic] # 142| 1: [Ident, VariableName] i # 142| Type = int # 142| 2: [Ident, VariableName] v diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected index 0a9335b397bd..d2ec9477f1de 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected @@ -33,10 +33,10 @@ input.go: # 20| 0: [CallExpr] call to Println # 20| Type = (int, error) # 20| 0: [FunctionName, SelectorExpr] selection of Println -# 20| Type = func([]any) int, error +# 20| Type = func([]any) int, error [variadic] # 20| 0: [Ident, PackageName] fmt # 20| 1: [FunctionName, Ident] Println -# 20| Type = func([]any) int, error +# 20| Type = func([]any) int, error [variadic] # 20| 1: [StringLit] "Hi" # 20| Type = string # 20| Value = [StringLit] Hi @@ -183,10 +183,10 @@ input.go: # 52| 0: [CallExpr] call to Println # 52| Type = (int, error) # 52| 0: [FunctionName, SelectorExpr] selection of Println -# 52| Type = func([]any) int, error +# 52| Type = func([]any) int, error [variadic] # 52| 0: [Ident, PackageName] fmt # 52| 1: [FunctionName, Ident] Println -# 52| Type = func([]any) int, error +# 52| Type = func([]any) int, error [variadic] # 52| 1: [StringLit] "Heard from ch1" # 52| Type = string # 52| Value = [StringLit] Heard from ch1 @@ -209,20 +209,20 @@ input.go: # 54| 0: [CallExpr] call to Println # 54| Type = (int, error) # 54| 0: [FunctionName, SelectorExpr] selection of Println -# 54| Type = func([]any) int, error +# 54| Type = func([]any) int, error [variadic] # 54| 0: [Ident, PackageName] fmt # 54| 1: [FunctionName, Ident] Println -# 54| Type = func([]any) int, error +# 54| Type = func([]any) int, error [variadic] # 54| 1: [Ident, VariableName] a # 54| Type = [1]float32 # 55| 2: [ExprStmt] expression statement # 55| 0: [CallExpr] call to Println # 55| Type = (int, error) # 55| 0: [FunctionName, SelectorExpr] selection of Println -# 55| Type = func([]any) int, error +# 55| Type = func([]any) int, error [variadic] # 55| 0: [Ident, PackageName] fmt # 55| 1: [FunctionName, Ident] Println -# 55| Type = func([]any) int, error +# 55| Type = func([]any) int, error [variadic] # 55| 1: [Ident, VariableName] w # 55| Type = bool # 56| 2: [CommClause] comm clause @@ -230,10 +230,10 @@ input.go: # 57| 0: [CallExpr] call to Println # 57| Type = (int, error) # 57| 0: [FunctionName, SelectorExpr] selection of Println -# 57| Type = func([]any) int, error +# 57| Type = func([]any) int, error [variadic] # 57| 0: [Ident, PackageName] fmt # 57| 1: [FunctionName, Ident] Println -# 57| Type = func([]any) int, error +# 57| Type = func([]any) int, error [variadic] # 58| 3: [CommClause] comm clause # 58| 0: [SendStmt] send statement # 58| 0: [Ident, VariableName] ch1 @@ -277,10 +277,10 @@ input.go: # 67| 0: [CallExpr] call to Println # 67| Type = (int, error) # 67| 0: [FunctionName, SelectorExpr] selection of Println -# 67| Type = func([]any) int, error +# 67| Type = func([]any) int, error [variadic] # 67| 0: [Ident, PackageName] fmt # 67| 1: [FunctionName, Ident] Println -# 67| Type = func([]any) int, error +# 67| Type = func([]any) int, error [variadic] # 67| 1: [Ident, VariableName] x # 67| Type = int # 68| 2: [BlockStmt] block statement @@ -296,10 +296,10 @@ input.go: # 69| 0: [CallExpr] call to Println # 69| Type = (int, error) # 69| 0: [FunctionName, SelectorExpr] selection of Println -# 69| Type = func([]any) int, error +# 69| Type = func([]any) int, error [variadic] # 69| 0: [Ident, PackageName] fmt # 69| 1: [FunctionName, Ident] Println -# 69| Type = func([]any) int, error +# 69| Type = func([]any) int, error [variadic] # 69| 1: [MinusExpr] -... # 69| Type = int # 69| 0: [Ident, VariableName] x @@ -454,10 +454,10 @@ input.go: # 115| 0: [CallExpr] call to Println # 115| Type = (int, error) # 115| 0: [FunctionName, SelectorExpr] selection of Println -# 115| Type = func([]any) int, error +# 115| Type = func([]any) int, error [variadic] # 115| 0: [Ident, PackageName] fmt # 115| 1: [FunctionName, Ident] Println -# 115| Type = func([]any) int, error +# 115| Type = func([]any) int, error [variadic] # 115| 1: [Ident, VariableName] y # 115| Type = interface { } # 116| 1: [CaseClause] case clause @@ -546,10 +546,10 @@ input.go: # 138| 0: [CallExpr] call to Print # 138| Type = (int, error) # 138| 0: [FunctionName, SelectorExpr] selection of Print -# 138| Type = func([]any) int, error +# 138| Type = func([]any) int, error [variadic] # 138| 0: [Ident, PackageName] fmt # 138| 1: [FunctionName, Ident] Print -# 138| Type = func([]any) int, error +# 138| Type = func([]any) int, error [variadic] # 138| 1: [Ident, VariableName] x # 138| Type = int # 141| 1: [RangeStmt] range statement @@ -564,10 +564,10 @@ input.go: # 142| 0: [CallExpr] call to Print # 142| Type = (int, error) # 142| 0: [FunctionName, SelectorExpr] selection of Print -# 142| Type = func([]any) int, error +# 142| Type = func([]any) int, error [variadic] # 142| 0: [Ident, PackageName] fmt # 142| 1: [FunctionName, Ident] Print -# 142| Type = func([]any) int, error +# 142| Type = func([]any) int, error [variadic] # 142| 1: [Ident, VariableName] i # 142| Type = int # 142| 2: [Ident, VariableName] v From d643c8513b721e5aed7bcaff40d7c0544d01d8d1 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 9 Sep 2024 11:42:57 +0100 Subject: [PATCH 36/36] Update stats --- go/ql/lib/go.dbscheme.stats | 12212 +++++++++++++++++++++------------- 1 file changed, 7714 insertions(+), 4498 deletions(-) diff --git a/go/ql/lib/go.dbscheme.stats b/go/ql/lib/go.dbscheme.stats index b18e8556fb24..50565d963aad 100644 --- a/go/ql/lib/go.dbscheme.stats +++ b/go/ql/lib/go.dbscheme.stats @@ -1,11 +1,15 @@ - @similarity + @duplication 0 - @duplication + @externalDataElement + 0 + + + @similarity 0 @@ -14,15 +18,11 @@ @xmlelement - 504 + 8655540 @xmlattribute - 408 - - - @externalDataElement - 0 + 3762921 @xmlnamespace @@ -30,667 +30,695 @@ @xmlcomment - 30 + 131455 @xmlcharacters - 869 + 13383839 @compilation - 1 + 31407 @diagnostic - 0 + 233782 @file - 529 + 146783 @folder - 210 + 98591 @comment_group - 12083 + 2493839 @slashslashcomment - 24878 + 2514613 @slashstarcomment - 846 + 77689 + + + @location_default + 37058201 @ident - 237316 + 5500549 @ellipsis - 141 + 42416 @intlit - 7683 - - - @floatlit - 27 + 8029312 @charlit - 838 + 44853 @stringlit - 24892 + 936836 @funclit - 678 + 145208 @compositelit - 2704 + 638762 @parenexpr - 343 + 44180 @selectorexpr - 54353 + 1563876 @indexexpr - 4581 + 1269900 @sliceexpr - 836 + 26235 @typeassertexpr - 2127 + 86701 @callorconversionexpr - 32041 + 1123396 @starexpr - 10360 + 401599 @keyvalueexpr - 5616 + 2321152 @arraytypeexpr - 3465 + 172175 @structtypeexpr - 1207 + 126802 @functypeexpr - 6015 + 302047 @interfacetypeexpr - 509 + 154636 @maptypeexpr - 1013 + 71689 @minusexpr - 270 + 183167 @notexpr - 1190 - - - @complementexpr - 21 + 36971 @addressexpr - 1739 + 112784 @arrowexpr - 92 + 27351 @lorexpr - 612 + 27296 @landexpr - 1234 + 99629 @eqlexpr - 3244 + 91950 @neqexpr - 4103 - - - @lssexpr - 785 - - - @leqexpr - 248 + 326490 @gtrexpr - 619 + 38816 @geqexpr - 270 + 21923 @addexpr - 1272 + 194589 @subexpr - 557 + 222492 - @orexpr - 146 + @mulexpr + 32053 - @xorexpr - 14 + @sendchantypeexpr + 22312 - @mulexpr - 207 + @recvchantypeexpr + 9117 - @quoexpr - 53 + @sendrcvchantypeexpr + 25432 - @remexpr - 24 + @badexpr + 2 - @shlexpr - 164 + @floatlit + 393088 - @shrexpr - 57 + @imaglit + 1233 - @andexpr - 235 + @genericfunctioninstantiationexpr + 9823 - @andnotexpr - 19 + @generictypeinstantiationexpr + 4188 - @sendchantypeexpr - 7 + @typesetliteralexpr + 1171 - @recvchantypeexpr - 9 + @plusexpr + 370 - @sendrcvchantypeexpr - 101 + @complementexpr + 3979 - @badexpr + @derefexpr 0 - @imaglit - 0 + @lssexpr + 32125 - @plusexpr - 0 + @leqexpr + 9262 - @derefexpr - 0 + @orexpr + 81746 - @field - 19974 + @xorexpr + 1753 - @location_default - 539178 + @quoexpr + 61619 - @declstmt - 1454 + @remexpr + 2999 - @labeledstmt - 49 + @shlexpr + 82494 + + + @shrexpr + 7813 + + + @andexpr + 11860 + + + @andnotexpr + 396 + + + @field + 995459 + + + @typeparamdecl + 9798 + + + @declstmt + 74013 @exprstmt - 7605 + 460278 @sendstmt - 69 + 16794 @incstmt - 614 + 15889 @decstmt - 71 + 9601 @gostmt - 72 + 20539 @deferstmt - 358 + 98332 @returnstmt - 9225 + 355294 @breakstmt - 301 + 14232 @continuestmt - 606 - - - @gotostmt - 8 - - - @fallthroughstmt - 7 + 45187 @blockstmt - 19358 + 539596 @ifstmt - 9728 + 313551 @caseclause - 3476 + 79016 @exprswitchstmt - 378 + 17092 @typeswitchstmt - 400 + 9269 @commclause - 72 + 25912 @selectstmt - 35 + 11996 @forstmt - 654 + 25752 @rangestmt - 2135 + 64694 @assignstmt - 7478 + 641512 @definestmt - 9514 + 433774 @addassignstmt - 223 + 21683 - @subassignstmt - 18 + @badstmt + 0 - @mulassignstmt - 5 + @emptystmt + 181 - @quoassignstmt - 3 + @labeledstmt + 4273 - @orassignstmt - 63 + @gotostmt + 4431 - @xorassignstmt - 3 + @fallthroughstmt + 11233 - @shlassignstmt - 2 + @subassignstmt + 6675 - @shrassignstmt - 3 + @mulassignstmt + 470 - @andnotassignstmt - 3 + @quoassignstmt + 556 - @badstmt - 0 + @remassignstmt + 171 - @emptystmt - 0 + @andassignstmt + 279 - @remassignstmt - 0 + @orassignstmt + 9913 - @andassignstmt - 0 + @xorassignstmt + 2562 + + + @shlassignstmt + 367 + + + @shrassignstmt + 429 + + + @andnotassignstmt + 279 @importdecl - 479 + 83355 @constdecl - 280 + 54489 @typedecl - 1349 + 100497 @vardecl - 1769 + 118650 @funcdecl - 4813 + 283367 @baddecl - 0 + 214 @importspec - 3468 + 247378 @valuespec - 3056 + 152556 @typedefspec - 1349 + 101666 @aliasspec - 16 + 17497 @universescope - 1 + 5401 @packagescope - 346 + 924779 @localscope - 36428 + 919952 @pkgobject - 3468 + 247378 @decltypeobject - 3602 + 13124885 @builtintypeobject - 20 + 118831 @declconstobject - 8857 + 80430386 @builtinconstobject - 4 + 21605 @declvarobject - 51098 + 118985930 @declfunctionobject - 17793 + 93191570 @builtinfunctionobject - 18 + 140437 @labelobject - 49 + 4273 @invalidtype - 1 + 5401 @boolexprtype - 1 + 5401 @inttype - 1 + 5401 @int8type - 1 + 5401 @int16type - 1 + 5401 @int32type - 1 + 5401 @int64type - 1 + 5401 @uinttype - 1 + 5401 @uint8type - 1 + 5401 @uint16type - 1 + 5401 @uint32type - 1 + 5401 @uint64type - 1 + 5401 @uintptrtype - 1 + 5401 @float32type - 1 + 5401 @float64type - 1 + 5401 @complex64type - 1 + 4107 @complex128type - 1 + 5401 @stringexprtype - 1 + 5401 @unsafepointertype - 1 + 5401 @boolliteraltype - 1 + 5401 @intliteraltype - 1 + 5401 @runeliteraltype - 1 + 5401 @floatliteraltype - 1 + 5401 @stringliteraltype - 1 + 5401 @nilliteraltype - 1 + 5401 + + + @typeparamtype + 331358 @arraytype - 293 + 1528173 @slicetype - 637 + 2313692 @structtype - 2409 + 8070007 @pointertype - 1903 + 8158995 @interfacetype - 247 + 1636684 @tupletype - 559 + 69835 @signaturetype - 8010 + 28950823 @maptype - 430 + 866786 @sendchantype - 13 + 32408 @recvchantype - 10 + 48612 @sendrcvchantype - 29 + 101202 @namedtype - 3567 + 12852686 + + + @typesetliteraltype + 59325 + + + @typealias + 660784 @complexliteraltype - 0 + 88 @package - 346 + 924779 @modline - 6 + 191935 @modlineblock - 1 + 22683 @modlparen - 1 + 22683 @modrparen - 1 + 22683 @modcommentblock - 0 + 431 @unknownerror @@ -698,15 +726,15 @@ @listerror - 0 + 22275 @parseerror - 0 + 3428 @typeerror - 0 + 219425 @@ -738,7 +766,7 @@ 1 2 - 1 + 403 @@ -754,7 +782,7 @@ 1 2 - 1 + 403 @@ -830,7 +858,7 @@ 1 2 - 1 + 403 @@ -846,7 +874,7 @@ 1 2 - 1 + 403 @@ -1383,11 +1411,11 @@ sourceLocationPrefix - 1 + 5401 prefix - 1 + 5401 @@ -1416,7 +1444,7 @@ 1 2 - 1 + 403 @@ -1470,7 +1498,7 @@ 1 2 - 1 + 403 @@ -1486,7 +1514,7 @@ 1 2 - 1 + 403 @@ -1502,7 +1530,7 @@ 1 2 - 1 + 403 @@ -1518,7 +1546,7 @@ 1 2 - 1 + 403 @@ -1688,27 +1716,27 @@ xmlElements - 504 + 8655540 id - 504 + 8655540 name - 38 + 160211 parentid - 199 + 2961862 idx - 86 + 1302233 fileid - 14 + 90375 @@ -1722,7 +1750,7 @@ 1 2 - 504 + 8655540 @@ -1738,7 +1766,7 @@ 1 2 - 504 + 8655540 @@ -1754,7 +1782,7 @@ 1 2 - 504 + 8655540 @@ -1770,7 +1798,7 @@ 1 2 - 504 + 8655540 @@ -1786,52 +1814,72 @@ 1 2 - 11 + 24647 2 3 - 3 + 8215 3 4 - 4 + 8215 4 + 5 + 12323 + + + 5 6 - 3 + 4107 - 7 - 12 - 3 + 8 + 9 + 12323 - 12 + 13 14 - 2 + 8215 - 14 - 16 - 3 + 18 + 22 + 12323 - 16 - 22 - 3 + 22 + 30 + 12323 - 27 + 30 40 - 3 + 12323 - 55 - 101 - 3 + 49 + 52 + 12323 + + + 52 + 58 + 8215 + + + 135 + 200 + 12323 + + + 233 + 570 + 12323 @@ -1847,47 +1895,57 @@ 1 2 - 15 + 49295 2 3 - 4 - - - 3 - 4 - 4 + 8215 4 5 - 3 + 20539 5 - 6 - 1 + 11 + 8215 - 6 - 7 - 3 + 11 + 12 + 8215 - 7 - 18 - 3 + 13 + 19 + 12323 - 18 + 19 22 - 3 + 12323 - 29 - 76 - 2 + 22 + 30 + 12323 + + + 33 + 53 + 12323 + + + 72 + 132 + 12323 + + + 302 + 303 + 4107 @@ -1903,52 +1961,52 @@ 1 2 - 12 + 41079 2 3 - 4 + 28755 3 4 - 5 + 12323 4 5 - 1 + 12323 5 6 - 3 + 12323 - 6 - 9 - 3 + 7 + 10 + 12323 - 10 - 11 - 2 + 11 + 14 + 12323 - 13 - 15 - 3 + 14 + 16 + 12323 - 15 - 17 - 3 + 33 + 50 + 12323 - 17 - 41 - 2 + 212 + 213 + 4107 @@ -1964,37 +2022,37 @@ 1 2 - 18 + 86267 2 3 - 7 + 12323 - 3 - 4 - 3 + 10 + 11 + 24647 - 4 - 5 - 1 + 13 + 19 + 8215 - 5 - 6 - 4 + 19 + 21 + 12323 - 7 - 11 - 3 + 21 + 22 + 8215 - 11 - 14 - 2 + 22 + 23 + 8215 @@ -2010,27 +2068,32 @@ 1 2 - 116 + 1429581 2 3 - 37 + 788734 3 4 - 22 + 172535 4 - 8 - 15 + 5 + 168427 - 8 - 61 - 9 + 5 + 7 + 267019 + + + 7 + 311 + 135563 @@ -2046,17 +2109,17 @@ 1 2 - 160 + 2185452 2 3 - 23 + 636738 3 - 8 - 16 + 10 + 139671 @@ -2072,27 +2135,32 @@ 1 2 - 116 + 1429581 2 3 - 37 + 788734 3 4 - 22 + 172535 4 - 8 - 15 + 5 + 168427 - 8 - 61 - 9 + 5 + 7 + 267019 + + + 7 + 311 + 135563 @@ -2108,7 +2176,7 @@ 1 2 - 199 + 2961862 @@ -2124,32 +2192,17 @@ 1 2 - 54 + 1125589 2 - 3 - 4 - - - 3 - 4 - 11 - - - 4 6 - 6 + 110915 6 - 21 - 7 - - - 40 - 141 - 4 + 404 + 65727 @@ -2165,32 +2218,17 @@ 1 2 - 54 + 1125589 2 3 - 5 + 106807 3 - 4 - 11 - - - 4 - 5 - 6 - - - 5 - 12 - 7 - - - 14 26 - 3 + 69835 @@ -2206,32 +2244,17 @@ 1 2 - 54 + 1125589 2 - 3 - 4 - - - 3 - 4 - 11 - - - 4 6 - 6 + 110915 6 - 21 - 7 - - - 40 - 141 - 4 + 404 + 65727 @@ -2247,32 +2270,12 @@ 1 2 - 54 + 1236505 2 - 3 - 4 - - - 3 - 4 - 11 - - - 4 - 5 - 8 - - - 5 - 13 - 7 - - - 13 - 15 - 2 + 23 + 65727 @@ -2286,64 +2289,49 @@ 12 - 2 - 3 - 1 - - - 7 - 8 - 1 + 6 + 7 + 4107 8 9 - 2 - - - 10 - 11 - 1 - - - 16 - 17 - 1 + 8215 - 18 - 19 - 1 + 9 + 10 + 12323 - 20 - 21 - 1 + 10 + 11 + 8215 - 21 - 22 - 2 + 13 + 16 + 8215 - 58 - 59 - 1 + 19 + 39 + 8215 - 100 - 101 - 1 + 40 + 41 + 4107 - 107 - 108 - 1 + 41 + 42 + 28755 - 108 - 109 - 1 + 67 + 1560 + 8215 @@ -2356,55 +2344,35 @@ 12 - - 2 - 3 - 1 - - - 3 - 4 - 2 - - - 4 - 5 - 1 - - - 5 - 6 - 2 - 6 7 - 2 + 8215 - 8 - 9 - 2 + 7 + 8 + 12323 - 11 - 12 - 1 + 8 + 9 + 20539 - 16 - 17 - 1 + 9 + 15 + 8215 - 17 - 18 - 1 + 15 + 16 + 36971 - 19 - 20 - 1 + 31 + 32 + 4107 @@ -2418,54 +2386,29 @@ 12 - 2 - 3 - 2 + 3 + 4 + 4107 4 5 - 1 - - - 6 - 7 - 2 - - - 7 - 8 - 3 - - - 9 - 10 - 1 - - - 10 - 11 - 1 - - - 20 - 21 - 1 + 32863 - 23 - 24 - 1 + 5 + 6 + 8215 - 47 - 48 - 1 + 13 + 14 + 36971 - 49 - 50 - 1 + 38 + 522 + 8215 @@ -2479,59 +2422,39 @@ 12 - 1 - 2 - 1 - - - 3 - 4 - 2 + 2 + 3 + 4107 - 4 - 5 - 1 + 5 + 6 + 24647 - 7 + 6 8 - 3 + 8215 - 8 - 9 - 1 + 11 + 13 + 8215 13 14 - 1 + 12323 14 15 - 1 + 24647 16 - 17 - 1 - - - 30 - 31 - 1 - - - 34 - 35 - 1 - - - 67 - 68 - 1 + 314 + 8215 @@ -2541,31 +2464,31 @@ xmlAttrs - 408 + 3762921 id - 408 + 3762921 elementid - 288 + 2744139 name - 28 + 180751 value - 235 + 1713032 idx - 6 + 20539 fileid - 14 + 90375 @@ -2579,7 +2502,7 @@ 1 2 - 408 + 3762921 @@ -2595,7 +2518,7 @@ 1 2 - 408 + 3762921 @@ -2611,7 +2534,7 @@ 1 2 - 408 + 3762921 @@ -2627,7 +2550,7 @@ 1 2 - 408 + 3762921 @@ -2643,7 +2566,7 @@ 1 2 - 408 + 3762921 @@ -2659,22 +2582,17 @@ 1 2 - 195 + 1963620 2 3 - 69 + 579226 3 - 4 - 23 - - - 6 - 7 - 1 + 6 + 201291 @@ -2690,22 +2608,17 @@ 1 2 - 195 + 1963620 2 3 - 69 + 579226 3 - 4 - 23 - - - 6 - 7 - 1 + 6 + 201291 @@ -2721,22 +2634,17 @@ 1 2 - 195 + 1963620 2 3 - 70 + 579226 3 - 4 - 22 - - - 4 - 5 - 1 + 6 + 201291 @@ -2752,22 +2660,17 @@ 1 2 - 195 + 1963620 2 3 - 69 + 579226 3 - 4 - 23 - - - 6 - 7 - 1 + 6 + 201291 @@ -2783,7 +2686,7 @@ 1 2 - 288 + 2744139 @@ -2799,42 +2702,42 @@ 1 2 - 12 + 65727 2 3 - 3 + 8215 3 4 - 4 + 24647 - 5 - 15 - 2 + 4 + 6 + 16431 - 21 - 22 - 2 + 8 + 12 + 16431 - 22 - 23 - 2 + 17 + 30 + 16431 - 45 - 97 - 2 + 30 + 50 + 16431 - 132 - 133 - 1 + 50 + 250 + 16431 @@ -2850,42 +2753,42 @@ 1 2 - 12 + 65727 2 3 - 3 + 8215 3 4 - 4 + 24647 - 5 - 15 - 2 + 4 + 6 + 16431 - 21 - 22 - 2 + 8 + 12 + 16431 - 22 - 23 - 2 + 17 + 30 + 16431 - 45 - 97 - 2 + 30 + 50 + 16431 - 132 - 133 - 1 + 50 + 250 + 16431 @@ -2901,37 +2804,32 @@ 1 2 - 16 + 94483 2 3 - 2 + 20539 3 4 - 3 - - - 11 - 12 - 1 + 20539 - 15 - 16 - 2 + 4 + 5 + 12323 - 21 - 36 - 2 + 5 + 14 + 16431 - 41 - 75 - 2 + 30 + 178 + 16431 @@ -2947,17 +2845,17 @@ 1 2 - 19 + 135563 2 3 - 5 + 28755 3 - 4 - 4 + 5 + 16431 @@ -2973,32 +2871,37 @@ 1 2 - 18 + 102699 2 3 - 2 + 12323 3 - 4 - 2 + 8 + 16431 - 4 - 6 - 2 + 9 + 12 + 16431 - 10 - 11 - 3 + 14 + 17 + 12323 - 13 - 14 - 1 + 17 + 18 + 12323 + + + 19 + 20 + 8215 @@ -3014,22 +2917,27 @@ 1 2 - 171 + 1294017 2 3 - 32 + 127347 3 5 - 18 + 139671 5 - 13 - 14 + 17 + 131455 + + + 19 + 31 + 20539 @@ -3045,22 +2953,27 @@ 1 2 - 174 + 1298125 2 3 - 29 + 127347 3 5 - 18 + 135563 5 - 13 - 14 + 17 + 131455 + + + 19 + 31 + 20539 @@ -3076,12 +2989,12 @@ 1 2 - 230 + 1688384 2 4 - 5 + 24647 @@ -3097,12 +3010,12 @@ 1 2 - 224 + 1671952 2 4 - 11 + 41079 @@ -3118,17 +3031,17 @@ 1 2 - 193 + 1474769 2 - 3 - 32 + 6 + 127347 - 3 - 7 - 10 + 9 + 20 + 110915 @@ -3142,24 +3055,29 @@ 12 - 1 - 2 - 3 + 3 + 4 + 4107 - 24 - 25 - 1 + 6 + 7 + 4107 + + + 49 + 50 + 4107 - 93 - 94 - 1 + 190 + 191 + 4107 - 288 - 289 - 1 + 668 + 669 + 4107 @@ -3173,24 +3091,29 @@ 12 - 1 - 2 - 3 + 3 + 4 + 4107 - 24 - 25 - 1 + 6 + 7 + 4107 - 93 - 94 - 1 + 49 + 50 + 4107 + + + 190 + 191 + 4107 - 288 - 289 - 1 + 668 + 669 + 4107 @@ -3204,24 +3127,29 @@ 12 - 1 - 2 - 3 + 2 + 3 + 4107 - 8 - 9 - 1 + 4 + 5 + 4107 - 14 - 15 - 1 + 9 + 10 + 4107 - 16 - 17 - 1 + 21 + 22 + 4107 + + + 25 + 26 + 4107 @@ -3235,24 +3163,29 @@ 12 - 1 - 2 - 3 + 3 + 4 + 4107 - 23 - 24 - 1 + 6 + 7 + 4107 - 64 - 65 - 1 + 21 + 22 + 4107 + + + 72 + 73 + 4107 - 157 - 158 - 1 + 326 + 327 + 4107 @@ -3266,24 +3199,19 @@ 12 - 1 - 2 - 3 - - - 6 - 7 - 1 - - - 12 - 13 - 1 + 3 + 4 + 8215 14 15 - 1 + 4107 + + + 22 + 23 + 8215 @@ -3297,64 +3225,54 @@ 12 - 2 - 3 - 1 + 3 + 4 + 4107 4 5 - 1 + 8215 - 10 - 11 - 2 + 9 + 10 + 4107 11 12 - 1 + 12323 12 - 13 - 1 - - - 17 - 18 - 1 + 14 + 8215 18 - 19 - 1 - - - 19 - 20 - 1 + 38 + 8215 - 22 - 23 - 1 + 39 + 40 + 12323 - 48 - 49 - 1 + 40 + 41 + 12323 - 73 - 74 - 2 + 41 + 42 + 12323 - 89 - 90 - 1 + 91 + 333 + 8215 @@ -3368,64 +3286,49 @@ 12 - 1 - 2 - 1 + 2 + 3 + 4107 - 4 - 5 - 1 + 3 + 4 + 8215 - 8 - 9 - 2 + 5 + 7 + 8215 - 9 - 10 - 1 + 7 + 8 + 12323 - 11 + 9 12 - 1 - - - 12 - 13 - 2 - - - 16 - 17 - 1 + 8215 17 18 - 1 - - - 18 - 19 - 1 + 4107 - 42 - 43 - 1 + 25 + 26 + 12323 - 63 - 64 - 1 + 26 + 27 + 24647 - 67 - 68 - 1 + 58 + 303 + 8215 @@ -3438,40 +3341,55 @@ 12 - - 2 - 3 - 2 - 3 4 - 2 + 4107 4 5 - 4 + 8215 5 6 - 1 + 4107 - 6 - 7 - 2 + 8 + 9 + 8215 - 7 - 8 - 2 + 9 + 10 + 12323 - 23 - 24 - 1 + 10 + 11 + 4107 + + + 11 + 12 + 12323 + + + 12 + 13 + 24647 + + + 13 + 17 + 8215 + + + 20 + 21 + 4107 @@ -3484,70 +3402,50 @@ 12 - - 2 - 3 - 1 - 3 4 - 1 - - - 6 - 7 - 1 + 4107 - 8 - 9 - 2 + 4 + 5 + 8215 9 10 - 1 + 4107 - 10 - 11 - 1 - - - 13 - 14 - 1 + 11 + 12 + 20539 - 14 - 15 - 1 + 17 + 27 + 8215 - 18 - 19 - 1 + 33 + 34 + 12323 - 32 - 33 - 1 + 34 + 35 + 12323 - 54 - 55 - 1 + 35 + 36 + 12323 60 - 61 - 1 - - - 61 - 62 - 1 + 244 + 8215 @@ -3560,25 +3458,20 @@ 12 - - 1 - 2 - 2 - 2 3 - 6 + 32863 3 4 - 5 + 45187 - 6 - 7 - 1 + 5 + 6 + 12323 @@ -3812,23 +3705,23 @@ xmlComments - 30 + 131455 id - 30 + 131455 text - 18 + 98591 parentid - 20 + 115023 fileid - 10 + 49295 @@ -3842,7 +3735,7 @@ 1 2 - 30 + 131455 @@ -3858,7 +3751,7 @@ 1 2 - 30 + 131455 @@ -3874,7 +3767,7 @@ 1 2 - 30 + 131455 @@ -3890,22 +3783,17 @@ 1 2 - 13 + 86267 - 2 - 3 - 3 + 3 + 4 + 4107 4 5 - 1 - - - 7 - 8 - 1 + 8215 @@ -3921,22 +3809,17 @@ 1 2 - 14 + 86267 - 2 - 3 - 2 + 3 + 4 + 4107 4 5 - 1 - - - 7 - 8 - 1 + 8215 @@ -3952,17 +3835,17 @@ 1 2 - 15 + 86267 - 2 - 3 - 2 + 3 + 4 + 4107 - 7 - 8 - 1 + 4 + 5 + 8215 @@ -3978,22 +3861,12 @@ 1 2 - 15 + 98591 2 3 - 3 - - - 4 - 5 - 1 - - - 5 - 6 - 1 + 16431 @@ -4009,22 +3882,12 @@ 1 2 - 15 + 98591 2 3 - 3 - - - 3 - 4 - 1 - - - 5 - 6 - 1 + 16431 @@ -4040,7 +3903,7 @@ 1 2 - 20 + 115023 @@ -4056,27 +3919,22 @@ 1 2 - 6 + 28755 2 3 - 1 - - - 4 - 5 - 1 + 12323 - 8 - 9 - 1 + 3 + 4 + 4107 - 10 - 11 - 1 + 16 + 17 + 4107 @@ -4092,27 +3950,22 @@ 1 2 - 6 + 28755 2 3 - 1 - - - 4 - 5 - 1 + 12323 - 5 - 6 - 1 + 3 + 4 + 4107 - 9 - 10 - 1 + 16 + 17 + 4107 @@ -4128,17 +3981,17 @@ 1 2 - 7 + 41079 - 3 - 4 - 1 + 2 + 3 + 4107 - 5 - 6 - 2 + 16 + 17 + 4107 @@ -4148,31 +4001,31 @@ xmlChars - 869 + 13383839 id - 869 + 13383839 text - 427 + 5862105 parentid - 432 + 6926075 idx - 87 + 1281693 isCDATA - 1 + 4107 fileid - 14 + 94483 @@ -4186,7 +4039,7 @@ 1 2 - 869 + 13383839 @@ -4202,7 +4055,7 @@ 1 2 - 869 + 13383839 @@ -4218,7 +4071,7 @@ 1 2 - 869 + 13383839 @@ -4234,7 +4087,7 @@ 1 2 - 869 + 13383839 @@ -4250,7 +4103,7 @@ 1 2 - 869 + 13383839 @@ -4266,22 +4119,17 @@ 1 2 - 339 + 5081586 2 - 3 - 53 - - - 3 - 49 - 33 + 4 + 480635 - 68 - 90 - 2 + 4 + 567 + 299883 @@ -4297,22 +4145,17 @@ 1 2 - 342 + 5098018 2 - 3 - 50 - - - 3 - 28 - 33 + 4 + 484743 - 28 - 32 - 2 + 4 + 179 + 279343 @@ -4328,12 +4171,12 @@ 1 2 - 400 + 5701893 2 - 58 - 27 + 298 + 160211 @@ -4349,7 +4192,7 @@ 1 2 - 427 + 5862105 @@ -4365,17 +4208,12 @@ 1 2 - 380 + 5710109 2 - 4 - 36 - - - 4 - 11 - 11 + 22 + 151995 @@ -4391,27 +4229,22 @@ 1 2 - 302 + 5328066 2 3 - 53 + 583334 3 - 4 - 28 - - - 4 - 7 - 34 + 5 + 521715 - 7 - 60 - 15 + 5 + 308 + 492959 @@ -4427,22 +4260,22 @@ 1 2 - 314 + 5664921 2 3 - 67 + 558686 3 - 5 - 37 + 7 + 595658 - 5 - 26 - 14 + 7 + 14 + 106807 @@ -4458,27 +4291,22 @@ 1 2 - 302 + 5328066 2 3 - 53 + 583334 3 - 4 - 28 - - - 4 - 7 - 34 + 5 + 521715 - 7 - 60 - 15 + 5 + 308 + 492959 @@ -4494,7 +4322,7 @@ 1 2 - 432 + 6926075 @@ -4510,7 +4338,7 @@ 1 2 - 432 + 6926075 @@ -4526,32 +4354,17 @@ 1 2 - 55 - - - 2 - 3 - 3 + 1105050 3 - 4 - 11 - - - 4 - 7 - 7 - - - 8 - 28 - 7 + 6 + 110915 - 41 - 408 - 4 + 6 + 1550 + 65727 @@ -4567,32 +4380,17 @@ 1 2 - 55 + 1105050 2 3 - 3 + 102699 3 - 4 - 12 - - - 4 - 7 - 7 - - - 7 - 28 - 7 - - - 44 - 251 - 3 + 923 + 73943 @@ -4608,32 +4406,17 @@ 1 2 - 55 - - - 2 - 3 - 3 + 1105050 3 - 4 - 11 - - - 4 - 7 - 7 - - - 8 - 28 - 7 + 6 + 110915 - 41 - 408 - 4 + 6 + 1550 + 65727 @@ -4649,7 +4432,7 @@ 1 2 - 87 + 1281693 @@ -4665,32 +4448,12 @@ 1 2 - 55 - - - 2 - 3 - 3 - - - 3 - 4 - 12 + 1215965 4 - 5 - 7 - - - 5 - 12 - 7 - - - 13 - 15 - 3 + 24 + 65727 @@ -4704,9 +4467,9 @@ 12 - 869 - 870 - 1 + 3258 + 3259 + 4107 @@ -4720,9 +4483,9 @@ 12 - 427 - 428 - 1 + 1427 + 1428 + 4107 @@ -4736,9 +4499,9 @@ 12 - 432 - 433 - 1 + 1686 + 1687 + 4107 @@ -4752,9 +4515,9 @@ 12 - 87 - 88 - 1 + 312 + 313 + 4107 @@ -4768,9 +4531,9 @@ 12 - 14 - 15 - 1 + 23 + 24 + 4107 @@ -4784,69 +4547,54 @@ 12 - 5 - 6 - 1 + 1 + 10 + 8215 - 13 - 14 - 1 + 11 + 13 + 8215 - 14 + 13 15 - 2 + 8215 - 17 - 18 - 1 + 15 + 16 + 4107 - 28 - 29 - 1 + 16 + 17 + 8215 - 30 - 31 - 1 + 18 + 21 + 8215 - 34 - 35 - 1 + 23 + 49 + 8215 - 35 - 36 - 1 + 51 + 52 + 4107 - 36 - 37 - 1 - - - 80 - 81 - 1 - - - 177 - 178 - 1 - - - 191 - 192 - 1 + 52 + 53 + 28755 - 195 - 196 - 1 + 118 + 2510 + 8215 @@ -4860,69 +4608,54 @@ 12 - 3 - 4 - 1 - - - 7 - 8 - 2 + 1 + 2 + 4107 - 9 - 10 - 1 + 4 + 5 + 16431 - 13 - 14 - 1 + 5 + 6 + 4107 - 15 - 16 - 1 + 6 + 7 + 12323 - 18 - 19 - 1 + 7 + 8 + 4107 - 24 - 25 - 1 + 8 + 9 + 8215 - 25 - 26 - 1 + 23 + 24 + 4107 26 27 - 1 - - - 49 - 50 - 1 - - - 100 - 101 - 1 + 28755 - 105 - 106 - 1 + 27 + 37 + 8215 - 118 - 119 - 1 + 1314 + 1315 + 4107 @@ -4936,64 +4669,44 @@ 12 - 3 - 4 - 1 - - - 7 - 8 - 1 - - - 9 - 10 - 2 - - - 10 - 11 - 1 - - - 14 - 15 - 1 + 1 + 2 + 4107 - 15 - 16 - 2 + 5 + 6 + 28755 - 18 - 19 - 1 + 6 + 7 + 8215 - 20 - 21 - 1 + 7 + 9 + 8215 - 33 - 34 - 1 + 23 + 24 + 4107 - 88 - 89 - 1 + 26 + 27 + 28755 - 95 - 96 - 1 + 27 + 55 + 8215 - 96 - 97 - 1 + 1337 + 1338 + 4107 @@ -5007,54 +4720,49 @@ 12 - 2 - 3 - 1 - - - 4 - 5 - 2 + 1 + 4 + 8215 - 5 - 6 - 1 + 6 + 7 + 8215 7 8 - 3 + 20539 - 9 - 10 - 1 + 8 + 9 + 8215 - 13 - 14 - 1 + 11 + 12 + 4107 - 15 - 16 - 2 + 12 + 13 + 8215 - 32 - 33 - 1 + 13 + 14 + 8215 - 35 - 36 - 1 + 14 + 15 + 24647 - 65 - 66 - 1 + 310 + 311 + 4107 @@ -5070,7 +4778,7 @@ 1 2 - 14 + 94483 @@ -5080,15 +4788,15 @@ xmllocations - 1825 + 26028241 xmlElement - 1825 + 26028241 location - 1825 + 26028241 @@ -5102,7 +4810,7 @@ 1 2 - 1825 + 26028241 @@ -5118,7 +4826,7 @@ 1 2 - 1825 + 26028241 @@ -5128,15 +4836,15 @@ compilations - 1 + 31407 id - 1 + 31407 cwd - 1 + 31407 @@ -5150,7 +4858,7 @@ 1 2 - 1 + 31407 @@ -5166,7 +4874,7 @@ 1 2 - 1 + 31407 @@ -5176,19 +4884,19 @@ compilation_args - 3 + 94222 id - 1 + 31407 num - 3 + 5234 arg - 3 + 5234 @@ -5202,7 +4910,7 @@ 3 4 - 1 + 31407 @@ -5218,7 +4926,7 @@ 3 4 - 1 + 31407 @@ -5232,9 +4940,9 @@ 12 - 1 - 2 - 3 + 18 + 19 + 5234 @@ -5250,7 +4958,7 @@ 1 2 - 3 + 5234 @@ -5264,9 +4972,9 @@ 12 - 1 - 2 - 3 + 18 + 19 + 5234 @@ -5282,7 +4990,7 @@ 1 2 - 3 + 5234 @@ -5436,23 +5144,23 @@ diagnostic_for - 0 + 233782 diagnostic - 0 + 233782 compilation - 0 + 214 file_number - 0 + 56356 file_number_diagnostic_number - 0 + 19713 @@ -5466,7 +5174,7 @@ 1 2 - 1 + 233782 @@ -5482,7 +5190,7 @@ 1 2 - 1 + 233782 @@ -5498,7 +5206,7 @@ 1 2 - 1 + 233782 @@ -5510,7 +5218,13 @@ 12 - + + + 1091 + 1092 + 214 + + @@ -5520,7 +5234,13 @@ 12 - + + + 263 + 264 + 214 + + @@ -5530,7 +5250,13 @@ 12 - + + + 92 + 93 + 214 + + @@ -5540,7 +5266,43 @@ 12 - + + + 1 + 2 + 26999 + + + 2 + 3 + 8142 + + + 3 + 4 + 5785 + + + 4 + 6 + 4928 + + + 6 + 11 + 4714 + + + 11 + 18 + 4285 + + + 18 + 93 + 1499 + + @@ -5550,7 +5312,13 @@ 12 - + + + 1 + 2 + 56356 + + @@ -5560,7 +5328,43 @@ 12 - + + + 1 + 2 + 26999 + + + 2 + 3 + 8142 + + + 3 + 4 + 5785 + + + 4 + 6 + 4928 + + + 6 + 11 + 4714 + + + 11 + 18 + 4285 + + + 18 + 93 + 1499 + + @@ -5570,47 +5374,125 @@ 12 - - - - - - file_number_diagnostic_number - compilation - - - 12 - - - - - - file_number_diagnostic_number - file_number - - - 12 - - + + + 1 + 2 + 6642 + + + 2 + 3 + 4714 + + + 3 + 4 + 3428 + + + 4 + 10 + 1499 + + + 10 + 33 + 1499 + + + 33 + 100 + 1499 + + + 137 + 264 + 428 + + + + + + + file_number_diagnostic_number + compilation + + + 12 + + + 1 + 2 + 19713 + + + + + + + file_number_diagnostic_number + file_number + + + 12 + + + 1 + 2 + 6642 + + + 2 + 3 + 4714 + + + 3 + 4 + 3428 + + + 4 + 10 + 1499 + + + 10 + 33 + 1499 + + + 33 + 100 + 1499 + + + 137 + 264 + 428 + + + compilation_finished - 1 + 31407 id - 1 + 31407 cpu_seconds - 1 + 1744 elapsed_seconds - 1 + 31407 @@ -5624,7 +5506,7 @@ 1 2 - 1 + 31407 @@ -5640,7 +5522,7 @@ 1 2 - 1 + 31407 @@ -5654,9 +5536,9 @@ 12 - 1 - 2 - 1 + 18 + 19 + 1744 @@ -5670,9 +5552,9 @@ 12 - 1 - 2 - 1 + 18 + 19 + 1744 @@ -5688,7 +5570,7 @@ 1 2 - 1 + 31407 @@ -5704,7 +5586,7 @@ 1 2 - 1 + 31407 @@ -5714,19 +5596,19 @@ compilation_compiling_files - 515 + 82070 id - 1 + 214 num - 515 + 82070 file - 515 + 82070 @@ -5738,9 +5620,9 @@ 12 - 515 - 516 - 1 + 383 + 384 + 214 @@ -5754,9 +5636,9 @@ 12 - 515 - 516 - 1 + 383 + 384 + 214 @@ -5772,7 +5654,7 @@ 1 2 - 515 + 82070 @@ -5788,7 +5670,7 @@ 1 2 - 515 + 82070 @@ -5804,7 +5686,7 @@ 1 2 - 515 + 82070 @@ -5820,7 +5702,7 @@ 1 2 - 515 + 82070 @@ -5830,31 +5712,31 @@ diagnostics - 0 + 233782 id - 0 + 233782 severity - 0 + 214 error_tag - 0 + 642 error_message - 0 + 56999 full_error_message - 0 + 56999 location - 0 + 149140 @@ -5868,7 +5750,7 @@ 1 2 - 1 + 233782 @@ -5884,7 +5766,7 @@ 1 2 - 1 + 233782 @@ -5900,7 +5782,7 @@ 1 2 - 1 + 233782 @@ -5916,7 +5798,7 @@ 1 2 - 1 + 233782 @@ -5932,7 +5814,7 @@ 1 2 - 1 + 233782 @@ -5944,7 +5826,13 @@ 12 - + + + 1091 + 1092 + 214 + + @@ -5954,7 +5842,13 @@ 12 - + + + 3 + 4 + 214 + + @@ -5964,7 +5858,13 @@ 12 - + + + 266 + 267 + 214 + + @@ -5974,7 +5874,13 @@ 12 - + + + 266 + 267 + 214 + + @@ -5984,7 +5890,13 @@ 12 - + + + 696 + 697 + 214 + + @@ -5994,7 +5906,23 @@ 12 - + + + 16 + 17 + 214 + + + 51 + 52 + 214 + + + 1024 + 1025 + 214 + + @@ -6004,7 +5932,13 @@ 12 - + + + 1 + 2 + 642 + + @@ -6014,7 +5948,23 @@ 12 - + + + 10 + 11 + 214 + + + 47 + 48 + 214 + + + 210 + 211 + 214 + + @@ -6024,7 +5974,23 @@ 12 - + + + 10 + 11 + 214 + + + 47 + 48 + 214 + + + 210 + 211 + 214 + + @@ -6034,7 +6000,23 @@ 12 - + + + 9 + 10 + 214 + + + 39 + 40 + 214 + + + 680 + 681 + 214 + + @@ -6044,7 +6026,38 @@ 12 - + + + 1 + 2 + 32142 + + + 2 + 3 + 8357 + + + 3 + 4 + 6428 + + + 4 + 7 + 4928 + + + 7 + 17 + 4285 + + + 20 + 214 + 857 + + @@ -6054,7 +6067,13 @@ 12 - + + + 1 + 2 + 56999 + + @@ -6064,7 +6083,18 @@ 12 - + + + 1 + 2 + 56784 + + + 2 + 3 + 214 + + @@ -6074,7 +6104,13 @@ 12 - + + + 1 + 2 + 56999 + + @@ -6084,27 +6120,90 @@ 12 - - - - - - full_error_message - id - - - 12 - - - - - - full_error_message - severity + + + 1 + 2 + 39642 + + + 2 + 3 + 6214 + + + 3 + 4 + 4071 + + + 4 + 8 + 4499 + + + 8 + 214 + 2571 + + + + + + + full_error_message + id 12 - + + + 1 + 2 + 32142 + + + 2 + 3 + 8357 + + + 3 + 4 + 6428 + + + 4 + 7 + 4928 + + + 7 + 17 + 4285 + + + 20 + 214 + 857 + + + + + + + full_error_message + severity + + + 12 + + + 1 + 2 + 56999 + + @@ -6114,7 +6213,18 @@ 12 - + + + 1 + 2 + 56784 + + + 2 + 3 + 214 + + @@ -6124,7 +6234,13 @@ 12 - + + + 1 + 2 + 56999 + + @@ -6134,7 +6250,33 @@ 12 - + + + 1 + 2 + 39642 + + + 2 + 3 + 6214 + + + 3 + 4 + 4071 + + + 4 + 8 + 4499 + + + 8 + 214 + 2571 + + @@ -6144,7 +6286,23 @@ 12 - + + + 1 + 2 + 133069 + + + 2 + 4 + 11571 + + + 4 + 93 + 4499 + + @@ -6154,7 +6312,13 @@ 12 - + + + 1 + 2 + 149140 + + @@ -6164,7 +6328,18 @@ 12 - + + + 1 + 2 + 142283 + + + 2 + 3 + 6857 + + @@ -6174,7 +6349,18 @@ 12 - + + + 1 + 2 + 142069 + + + 2 + 15 + 7071 + + @@ -6184,7 +6370,18 @@ 12 - + + + 1 + 2 + 142069 + + + 2 + 15 + 7071 + + @@ -6192,31 +6389,31 @@ locations_default - 539178 + 37058201 id - 539178 + 37058201 file - 529 + 115023 beginLine - 10312 + 6174312 beginColumn - 211 + 1026998 endLine - 10378 + 7357414 endColumn - 274 + 1154345 @@ -6230,7 +6427,7 @@ 1 2 - 539178 + 37058201 @@ -6246,7 +6443,7 @@ 1 2 - 539178 + 37058201 @@ -6262,7 +6459,7 @@ 1 2 - 539178 + 37058201 @@ -6278,7 +6475,7 @@ 1 2 - 539178 + 37058201 @@ -6294,7 +6491,7 @@ 1 2 - 539178 + 37058201 @@ -6308,74 +6505,74 @@ 12 - 4 - 39 - 41 + 2 + 24 + 8215 - 39 - 120 - 40 + 28 + 30 + 8215 - 120 - 208 - 40 + 33 + 38 + 8215 - 210 - 290 - 40 + 38 + 39 + 8215 - 291 - 372 - 40 + 44 + 48 + 8215 - 372 - 453 - 41 + 58 + 68 + 8215 - 456 - 563 - 40 + 72 + 86 + 8215 - 565 - 769 - 40 + 126 + 132 + 8215 - 774 - 1007 - 40 + 133 + 134 + 4107 - 1012 - 1339 - 42 + 134 + 135 + 12323 - 1347 - 1700 - 40 + 135 + 136 + 12323 - 1701 - 2804 - 40 + 211 + 279 + 8215 - 2873 - 6918 - 40 + 1057 + 1261 + 8215 - 8171 - 11207 - 5 + 4417 + 4418 + 4107 @@ -6389,69 +6586,64 @@ 12 - 3 - 15 - 44 - - - 15 - 27 - 42 + 2 + 11 + 8215 - 27 - 46 - 40 + 12 + 14 + 8215 - 46 - 63 - 43 + 14 + 16 + 8215 - 63 - 78 - 40 + 16 + 17 + 4107 - 78 - 94 - 41 + 17 + 18 + 8215 - 95 - 120 - 40 + 20 + 21 + 8215 - 120 - 152 - 41 + 21 + 24 + 8215 - 152 - 188 - 40 + 28 + 34 + 8215 - 189 - 247 - 41 + 34 + 35 + 32863 - 249 - 325 - 40 + 40 + 109 + 8215 - 336 - 544 - 40 + 168 + 228 + 8215 - 554 - 10233 - 37 + 1355 + 1356 + 4107 @@ -6465,69 +6657,79 @@ 12 - 3 - 16 - 40 + 2 + 18 + 8215 - 16 - 34 - 40 + 19 + 20 + 8215 - 34 - 44 - 40 + 21 + 22 + 8215 - 45 - 51 - 44 + 22 + 23 + 8215 - 51 - 58 - 41 + 23 + 24 + 8215 - 58 - 63 - 47 + 25 + 27 + 8215 - 63 - 68 - 44 + 32 + 59 + 8215 - 68 - 73 - 43 + 60 + 65 + 8215 - 73 - 80 - 47 + 65 + 67 + 8215 - 80 - 86 - 43 + 67 + 68 + 4107 - 86 - 98 - 42 + 68 + 69 + 8215 - 98 - 115 - 42 + 69 + 70 + 4107 + + + 70 + 71 + 8215 + + + 80 + 93 + 8215 - 115 - 157 - 16 + 101 + 132 + 8215 @@ -6541,74 +6743,69 @@ 12 - 3 - 16 - 41 - - - 16 - 31 - 40 + 2 + 12 + 8215 - 31 - 52 - 40 + 12 + 14 + 8215 - 52 - 73 - 43 + 14 + 15 + 4107 - 73 - 92 - 42 + 15 + 16 + 8215 - 92 - 111 - 40 + 16 + 17 + 8215 - 111 - 139 - 40 + 19 + 20 + 8215 - 139 - 180 - 40 + 26 + 29 + 8215 - 180 - 219 - 40 + 30 + 38 + 8215 - 223 - 293 - 40 + 38 + 39 + 20539 - 294 - 370 - 40 + 39 + 40 + 12323 - 373 - 616 - 40 + 40 + 110 + 8215 - 617 - 1835 - 40 + 202 + 266 + 8215 - 2166 - 10377 - 3 + 1676 + 1677 + 4107 @@ -6622,69 +6819,79 @@ 12 - 4 - 21 - 42 + 2 + 17 + 8215 - 22 - 45 - 41 + 18 + 20 + 8215 - 46 - 59 - 43 + 23 + 25 + 8215 - 59 - 65 - 40 + 25 + 26 + 8215 - 65 - 71 - 42 + 26 + 31 + 8215 - 71 - 76 - 47 + 33 + 41 + 8215 - 76 - 81 - 40 + 42 + 61 + 8215 - 81 - 85 - 48 + 71 + 72 + 4107 85 - 91 - 41 + 86 + 8215 - 91 - 97 - 42 + 86 + 87 + 4107 - 97 - 105 - 41 + 88 + 89 + 8215 - 105 - 119 - 42 + 89 + 91 + 8215 - 119 - 166 - 20 + 91 + 92 + 8215 + + + 92 + 102 + 8215 + + + 125 + 149 + 8215 @@ -6700,32 +6907,47 @@ 1 2 - 6869 + 1142021 2 - 7 - 843 + 3 + 1092726 - 7 - 20 - 796 + 3 + 4 + 1039322 - 20 - 80 - 780 + 4 + 5 + 603874 - 80 - 698 - 774 + 5 + 6 + 612090 - 699 - 1775 - 250 + 6 + 7 + 390259 + + + 7 + 9 + 546363 + + + 9 + 21 + 484743 + + + 21 + 179 + 262911 @@ -6741,32 +6963,22 @@ 1 2 - 6947 + 5311634 2 3 - 868 + 353287 3 - 6 - 899 - - - 6 - 24 - 774 - - - 24 - 304 - 774 + 22 + 464203 - 305 - 530 - 50 + 22 + 29 + 45187 @@ -6782,32 +6994,47 @@ 1 2 - 6894 + 1146129 2 + 3 + 1121481 + + + 3 + 4 + 1051646 + + + 4 5 - 789 + 665494 5 - 11 - 780 + 6 + 624414 - 11 - 30 - 796 + 6 + 7 + 402583 - 30 - 72 - 779 + 7 + 8 + 517607 - 72 - 115 - 274 + 8 + 17 + 497067 + + + 17 + 57 + 147887 @@ -6823,27 +7050,17 @@ 1 2 - 7630 + 2690735 2 3 - 1017 + 3031698 3 - 6 - 779 - - - 6 - 21 - 792 - - - 21 - 315 - 94 + 14 + 451879 @@ -6859,32 +7076,47 @@ 1 2 - 6871 + 1630873 2 + 3 + 624414 + + + 3 + 4 + 1063970 + + + 4 5 - 793 + 636738 5 - 12 - 789 + 6 + 644954 - 12 - 33 - 778 + 6 + 7 + 480635 - 33 - 81 - 781 + 7 + 9 + 464203 - 81 - 127 - 300 + 9 + 19 + 476527 + + + 19 + 65 + 151995 @@ -6900,67 +7132,52 @@ 1 2 - 29 + 308099 2 - 4 - 19 - - - 4 - 9 - 16 - - - 10 - 22 - 16 - - - 22 - 62 - 16 + 3 + 127347 - 62 - 141 - 16 + 3 + 5 + 94483 - 144 - 330 - 16 + 5 + 8 + 90375 - 330 - 759 - 16 + 9 + 16 + 82159 - 781 - 1804 - 16 + 16 + 35 + 78051 - 1846 - 3757 - 16 + 35 + 66 + 78051 - 4042 - 8613 - 16 + 72 + 105 + 78051 - 8764 - 22092 - 16 + 105 + 408 + 78051 - 28067 - 55590 - 3 + 500 + 1007 + 12323 @@ -6976,62 +7193,47 @@ 1 2 - 36 + 320423 2 - 4 - 14 - - - 4 - 10 - 18 - - - 10 - 22 - 17 - - - 22 - 48 - 17 + 3 + 151995 - 49 - 96 - 17 + 3 + 4 + 53403 - 96 - 180 - 16 + 4 + 5 + 90375 - 180 - 292 - 16 + 5 + 6 + 98591 - 297 - 382 - 16 + 6 + 9 + 82159 - 383 - 430 - 16 + 9 + 13 + 69835 - 431 - 463 - 16 + 13 + 17 + 78051 - 463 - 530 - 12 + 17 + 29 + 82159 @@ -7047,67 +7249,47 @@ 1 2 - 36 + 394367 2 - 4 - 13 - - - 4 - 9 - 16 - - - 9 - 20 - 16 - - - 20 - 53 - 16 - - - 55 - 103 - 16 + 3 + 143779 - 107 - 209 - 16 + 3 + 5 + 86267 - 221 - 412 - 16 + 5 + 14 + 78051 - 422 - 682 - 16 + 14 + 32 + 82159 - 706 - 975 - 16 + 32 + 58 + 78051 - 977 - 1410 - 16 + 61 + 82 + 82159 - 1417 - 1983 - 16 + 83 + 623 + 78051 - 2809 - 10184 - 2 + 752 + 753 + 4107 @@ -7123,62 +7305,47 @@ 1 2 - 36 + 394367 2 - 4 - 13 - - - 4 - 9 - 16 - - - 9 - 21 - 19 - - - 24 - 55 - 16 + 3 + 143779 - 58 - 128 - 16 + 3 + 5 + 86267 - 131 - 226 - 16 + 5 + 14 + 78051 - 231 - 453 - 16 + 14 + 31 + 78051 - 480 - 769 - 16 + 31 + 56 + 78051 - 783 - 1037 - 16 + 57 + 80 + 82159 - 1057 - 1521 - 16 + 81 + 412 + 78051 - 1526 - 10180 - 15 + 627 + 773 + 8215 @@ -7194,62 +7361,42 @@ 1 2 - 31 + 468311 2 3 - 16 + 94483 3 - 6 - 17 - - - 6 - 12 - 17 - - - 12 - 21 - 16 - - - 21 - 28 - 16 - - - 28 - 35 - 17 + 5 + 78051 - 35 - 45 - 16 + 5 + 13 + 78051 - 46 - 56 - 16 + 13 + 23 + 90375 - 56 - 77 - 17 + 25 + 34 + 82159 - 77 - 101 - 17 + 34 + 41 + 82159 - 101 - 201 - 15 + 41 + 106 + 53403 @@ -7265,32 +7412,47 @@ 1 2 - 6731 + 3093318 2 + 3 + 505283 + + + 3 + 4 + 796950 + + + 4 + 5 + 801058 + + + 5 6 - 903 + 443663 6 - 16 - 817 + 7 + 303991 - 16 - 58 - 785 + 7 + 8 + 579226 - 58 - 457 - 779 + 8 + 21 + 562794 - 458 - 1734 - 363 + 21 + 174 + 271127 @@ -7306,32 +7468,22 @@ 1 2 - 6847 + 6318092 2 3 - 810 + 382043 3 - 5 - 787 - - - 5 - 14 - 802 - - - 14 - 104 - 780 + 16 + 554578 - 105 - 530 - 352 + 16 + 29 + 102699 @@ -7347,27 +7499,17 @@ 1 2 - 7766 + 4962455 2 3 - 956 + 1934864 3 - 7 - 860 - - - 7 - 27 - 785 - - - 27 - 31 - 11 + 8 + 460095 @@ -7383,32 +7525,47 @@ 1 2 - 6749 + 3101534 2 + 3 + 521715 + + + 3 4 - 616 + 813382 4 - 8 - 878 + 5 + 870894 - 8 - 21 - 799 + 5 + 6 + 468311 - 21 - 53 - 779 + 6 + 7 + 308099 - 53 - 113 - 557 + 7 + 8 + 640846 + + + 8 + 24 + 562794 + + + 24 + 54 + 69835 @@ -7424,32 +7581,47 @@ 1 2 - 6792 + 3130290 2 + 3 + 529931 + + + 3 + 4 + 796950 + + + 4 5 - 936 + 854462 5 - 12 - 801 + 6 + 443663 - 12 - 34 - 791 + 6 + 7 + 414907 - 34 - 83 - 787 + 7 + 9 + 583334 - 83 - 127 - 271 + 9 + 32 + 554578 + + + 33 + 66 + 49295 @@ -7465,57 +7637,57 @@ 1 2 - 33 + 262911 2 3 - 60 + 180751 3 - 9 - 23 + 4 + 32863 - 9 - 40 - 21 + 4 + 5 + 98591 - 43 - 111 - 21 + 5 + 7 + 90375 - 121 - 347 - 21 + 7 + 15 + 90375 - 369 - 1229 - 21 + 15 + 37 + 90375 - 1267 - 3311 - 21 + 40 + 71 + 90375 - 3642 - 7560 - 21 + 71 + 101 + 90375 - 7682 - 12716 - 21 + 101 + 144 + 90375 - 12740 - 20483 - 11 + 146 + 448 + 36971 @@ -7531,52 +7703,52 @@ 1 2 - 94 + 312207 2 - 6 - 19 + 3 + 156103 - 6 - 16 - 21 + 3 + 4 + 53403 - 16 - 45 - 21 + 4 + 5 + 119131 - 45 - 110 - 21 + 5 + 6 + 94483 - 123 - 281 - 21 + 6 + 9 + 102699 - 290 - 393 - 21 + 9 + 12 + 90375 - 395 - 445 - 21 + 12 + 15 + 82159 - 446 - 468 - 21 + 15 + 19 + 94483 - 470 - 530 - 14 + 19 + 29 + 49295 @@ -7592,52 +7764,47 @@ 1 2 - 94 + 414907 2 - 6 - 19 - - - 6 - 21 - 21 + 3 + 160211 - 21 - 52 - 21 + 3 + 5 + 102699 - 54 - 154 - 21 + 5 + 11 + 94483 - 157 - 449 - 21 + 11 + 38 + 90375 - 455 - 808 - 21 + 40 + 66 + 90375 - 814 - 1132 - 21 + 67 + 86 + 90375 - 1145 - 1769 - 21 + 86 + 126 + 94483 - 1792 - 2365 - 14 + 126 + 352 + 16431 @@ -7653,57 +7820,47 @@ 1 2 - 39 + 460095 2 3 - 56 + 102699 3 - 7 - 23 + 4 + 69835 - 7 - 18 - 21 - - - 18 - 27 - 24 - - - 27 - 37 - 22 + 4 + 8 + 106807 - 37 - 49 - 23 + 8 + 16 + 94483 - 49 - 63 - 22 + 16 + 26 + 94483 - 63 - 74 - 20 + 26 + 31 + 86267 - 74 - 102 - 21 + 31 + 35 + 94483 - 103 - 172 - 3 + 35 + 58 + 45187 @@ -7719,52 +7876,47 @@ 1 2 - 94 + 414907 2 - 6 - 19 - - - 6 - 21 - 21 + 3 + 160211 - 21 - 52 - 21 + 3 + 5 + 102699 - 53 - 153 - 21 + 5 + 11 + 94483 - 156 - 444 - 21 + 11 + 38 + 90375 - 446 - 789 - 21 + 40 + 67 + 94483 - 806 - 1121 - 21 + 68 + 87 + 90375 - 1138 - 1726 - 21 + 87 + 127 + 90375 - 1787 - 2357 - 14 + 131 + 394 + 16431 @@ -7774,23 +7926,23 @@ numlines - 514 + 81641 element_id - 514 + 81641 num_lines - 309 + 22071 num_code - 350 + 17999 num_comment - 150 + 10928 @@ -7804,7 +7956,7 @@ 1 2 - 514 + 81641 @@ -7820,7 +7972,7 @@ 1 2 - 514 + 81641 @@ -7836,7 +7988,7 @@ 1 2 - 514 + 81641 @@ -7852,22 +8004,47 @@ 1 2 - 183 + 7285 2 3 - 74 + 3857 3 4 - 32 + 1285 4 + 5 + 2142 + + + 5 + 6 + 1928 + + + 6 7 - 20 + 1928 + + + 7 + 9 + 1285 + + + 9 + 11 + 1285 + + + 11 + 12 + 1071 @@ -7883,22 +8060,37 @@ 1 2 - 187 + 8357 2 3 - 82 + 3642 3 4 - 23 + 2142 4 - 7 - 17 + 5 + 2357 + + + 5 + 6 + 2785 + + + 6 + 8 + 1928 + + + 8 + 10 + 857 @@ -7914,22 +8106,37 @@ 1 2 - 188 + 8785 2 3 - 79 + 3857 3 4 - 28 + 2357 4 + 5 + 2357 + + + 5 + 6 + 1928 + + + 6 7 - 14 + 1285 + + + 7 + 10 + 1499 @@ -7945,22 +8152,37 @@ 1 2 - 252 + 6214 2 3 - 65 + 4071 3 - 5 - 28 + 4 + 2142 - 6 - 18 - 5 + 5 + 8 + 1285 + + + 8 + 10 + 1285 + + + 10 + 13 + 1499 + + + 14 + 22 + 1499 @@ -7976,17 +8198,42 @@ 1 2 - 256 + 7071 2 3 - 67 + 3428 3 + 4 + 2142 + + + 4 + 7 + 1499 + + + 7 + 9 + 1285 + + + 9 + 10 + 857 + + + 10 + 15 + 1499 + + + 17 18 - 27 + 214 @@ -8002,22 +8249,37 @@ 1 2 - 259 + 7071 2 3 - 63 + 3428 3 + 4 + 2142 + + + 4 + 6 + 857 + + + 6 7 - 27 + 1714 - 17 - 18 - 1 + 7 + 9 + 1499 + + + 9 + 16 + 1285 @@ -8033,37 +8295,47 @@ 1 2 - 65 + 3214 2 3 - 27 + 2142 3 4 - 17 + 1285 4 - 5 - 7 + 7 + 642 - 5 - 6 - 10 + 7 + 8 + 428 - 6 - 10 - 12 + 8 + 9 + 1071 - 10 - 31 - 12 + 11 + 18 + 857 + + + 18 + 28 + 857 + + + 37 + 84 + 428 @@ -8079,37 +8351,47 @@ 1 2 - 65 + 3214 2 3 - 27 + 2357 3 4 - 18 + 1285 4 5 - 7 + 214 - 5 - 6 - 10 + 6 + 7 + 857 - 6 - 10 - 13 + 7 + 9 + 857 10 - 25 - 10 + 13 + 642 + + + 14 + 16 + 857 + + + 22 + 39 + 642 @@ -8125,37 +8407,47 @@ 1 2 - 66 + 3214 2 3 - 27 + 2357 3 4 - 17 + 1285 4 - 5 - 6 - - - 5 6 - 10 + 642 6 - 9 - 12 + 8 + 642 - 9 - 24 - 12 + 8 + 10 + 857 + + + 10 + 14 + 857 + + + 14 + 26 + 857 + + + 33 + 34 + 214 @@ -8165,15 +8457,15 @@ files - 529 + 146783 id - 529 + 146783 name - 529 + 146783 @@ -8187,7 +8479,7 @@ 1 2 - 529 + 146783 @@ -8203,7 +8495,7 @@ 1 2 - 529 + 146783 @@ -8213,15 +8505,15 @@ folders - 210 + 98591 id - 210 + 98591 name - 210 + 98591 @@ -8235,7 +8527,7 @@ 1 2 - 210 + 98591 @@ -8251,7 +8543,7 @@ 1 2 - 210 + 98591 @@ -8261,15 +8553,15 @@ containerparent - 738 + 243853 parent - 210 + 97284 child - 738 + 243853 @@ -8283,32 +8575,27 @@ 1 2 - 115 + 56142 2 3 - 32 + 21856 3 4 - 12 + 6214 4 - 6 - 19 - - - 6 - 12 - 16 + 7 + 8357 - 13 - 38 - 16 + 7 + 95 + 4714 @@ -8324,7 +8611,7 @@ 1 2 - 738 + 243853 @@ -8334,15 +8621,15 @@ has_location - 599339 + 14587326 locatable - 599339 + 14587326 location - 537353 + 11868805 @@ -8356,7 +8643,7 @@ 1 2 - 599339 + 14587326 @@ -8372,17 +8659,12 @@ 1 2 - 475682 + 9150285 2 3 - 61627 - - - 3 - 75 - 44 + 2718520 @@ -8392,19 +8674,19 @@ comment_groups - 12083 + 2493839 id - 12083 + 2493839 parent - 509 + 3187 idx - 720 + 846614 @@ -8418,7 +8700,7 @@ 1 2 - 12083 + 2493839 @@ -8434,7 +8716,7 @@ 1 2 - 12083 + 2493839 @@ -8450,67 +8732,52 @@ 1 2 - 44 + 691 2 3 - 45 + 384 3 4 - 32 + 230 4 - 5 - 27 - - - 5 - 7 - 38 - - - 7 - 10 - 47 + 6 + 268 - 10 - 13 - 34 + 6 + 12 + 268 - 13 - 17 - 47 + 12 + 18 + 230 - 17 - 23 - 40 + 18 + 24 + 268 - 23 - 29 - 40 + 34 + 110 + 230 - 29 - 38 - 39 + 256 + 257 + 460 - 38 - 70 - 39 - - - 70 - 721 - 37 + 7980 + 22048 + 153 @@ -8526,67 +8793,52 @@ 1 2 - 44 + 691 2 3 - 45 + 384 3 4 - 32 + 230 4 - 5 - 27 - - - 5 - 7 - 38 - - - 7 - 10 - 47 - - - 10 - 13 - 34 + 6 + 268 - 13 - 17 - 47 + 6 + 12 + 268 - 17 - 23 - 40 + 12 + 18 + 230 - 23 - 29 - 40 + 18 + 24 + 268 - 29 - 38 - 39 + 34 + 110 + 230 - 38 - 70 - 39 + 256 + 257 + 460 - 70 - 721 - 37 + 7980 + 22048 + 153 @@ -8602,37 +8854,27 @@ 1 2 - 429 + 182133 2 3 - 53 + 136129 3 - 8 - 66 + 4 + 221916 - 8 - 16 - 57 + 4 + 5 + 296604 16 - 44 - 54 - - - 44 - 311 - 54 - - - 323 - 510 - 7 + 84 + 9830 @@ -8648,37 +8890,27 @@ 1 2 - 429 + 182133 2 3 - 53 + 136129 3 - 8 - 66 + 4 + 221916 - 8 - 16 - 57 + 4 + 5 + 296604 16 - 44 - 54 - - - 44 - 311 - 54 - - - 323 - 510 - 7 + 84 + 9830 @@ -8688,27 +8920,27 @@ comments - 25724 + 2514805 id - 25724 + 2514805 kind - 2 + 76 parent - 12083 + 2493839 idx - 156 + 1728 text - 20683 + 541522 @@ -8722,7 +8954,7 @@ 1 2 - 25724 + 2514805 @@ -8738,7 +8970,7 @@ 1 2 - 25724 + 2514805 @@ -8754,7 +8986,7 @@ 1 2 - 25724 + 2514805 @@ -8770,7 +9002,7 @@ 1 2 - 25724 + 2514805 @@ -8784,14 +9016,14 @@ 12 - 846 - 847 - 1 + 5 + 6 + 38 - 24878 - 24879 - 1 + 65484 + 65485 + 38 @@ -8805,14 +9037,14 @@ 12 - 846 - 847 - 1 + 5 + 6 + 38 - 11239 - 11240 - 1 + 64938 + 64939 + 38 @@ -8826,14 +9058,14 @@ 12 - 2 - 3 - 1 + 1 + 2 + 38 - 156 - 157 - 1 + 45 + 46 + 38 @@ -8847,14 +9079,14 @@ 12 - 690 - 691 - 1 + 5 + 6 + 38 - 19993 - 19994 - 1 + 14097 + 14098 + 38 @@ -8870,27 +9102,12 @@ 1 2 - 7828 + 2484930 2 - 3 - 1787 - - - 3 - 4 - 1289 - - - 4 - 11 - 937 - - - 11 - 157 - 242 + 46 + 8908 @@ -8906,12 +9123,7 @@ 1 2 - 12081 - - - 2 - 3 - 2 + 2493839 @@ -8927,27 +9139,12 @@ 1 2 - 7828 + 2484930 2 - 3 - 1787 - - - 3 - 4 - 1289 - - - 4 - 11 - 937 - - - 11 - 157 - 242 + 46 + 8908 @@ -8963,27 +9160,12 @@ 1 2 - 7828 + 2484930 2 - 3 - 1817 - - - 3 - 4 - 1275 - - - 4 - 10 - 937 - - - 10 - 131 - 226 + 33 + 8908 @@ -8999,57 +9181,32 @@ 1 2 - 36 + 921 2 - 4 - 13 - - - 4 - 5 - 16 + 3 + 307 5 - 7 - 12 - - - 7 - 9 - 12 - - - 9 - 11 - 6 - - - 12 - 14 - 13 - - - 14 - 24 - 13 + 10 + 153 - 26 - 52 - 12 + 11 + 20 + 153 - 59 - 218 - 12 + 34 + 233 + 153 - 242 - 12084 - 11 + 64943 + 64944 + 38 @@ -9065,12 +9222,12 @@ 1 2 - 154 + 1689 2 3 - 2 + 38 @@ -9086,57 +9243,32 @@ 1 2 - 36 + 921 2 - 4 - 13 - - - 4 - 5 - 16 + 3 + 307 5 - 7 - 12 - - - 7 - 9 - 12 - - - 9 - 11 - 6 - - - 12 - 14 - 13 - - - 14 - 24 - 13 + 10 + 153 - 26 - 52 - 12 + 11 + 20 + 153 - 59 - 218 - 12 + 34 + 233 + 153 - 242 - 12084 - 11 + 64943 + 64944 + 38 @@ -9152,52 +9284,32 @@ 1 2 - 36 + 960 2 - 4 - 14 + 3 + 268 4 - 5 - 18 - - - 5 - 7 - 14 - - - 7 - 9 - 11 - - - 9 - 12 - 14 - - - 12 - 17 - 12 + 8 + 153 - 19 - 36 - 13 + 8 + 15 + 153 - 39 - 128 - 12 + 29 + 188 + 153 - 165 - 10500 - 12 + 13716 + 13717 + 38 @@ -9213,12 +9325,17 @@ 1 2 - 19550 + 494827 2 - 1935 - 1133 + 12 + 40819 + + + 12 + 45601 + 5875 @@ -9234,7 +9351,7 @@ 1 2 - 20683 + 541522 @@ -9250,12 +9367,17 @@ 1 2 - 19575 + 494904 2 - 828 - 1108 + 12 + 40742 + + + 12 + 45601 + 5875 @@ -9271,12 +9393,12 @@ 1 2 - 20523 + 540255 2 - 107 - 160 + 18 + 1267 @@ -9286,15 +9408,15 @@ doc_comments - 4330 + 273911 node - 4330 + 273911 comment - 4330 + 273911 @@ -9308,7 +9430,7 @@ 1 2 - 4330 + 273911 @@ -9324,7 +9446,7 @@ 1 2 - 4330 + 273911 @@ -9334,23 +9456,23 @@ exprs - 414037 + 8869156 id - 414037 + 8869156 kind - 48 + 14536 parent - 219324 + 4516748 idx - 5163 + 258019 @@ -9364,7 +9486,7 @@ 1 2 - 414037 + 8869156 @@ -9380,7 +9502,7 @@ 1 2 - 414037 + 8869156 @@ -9396,7 +9518,7 @@ 1 2 - 414037 + 8869156 @@ -9410,64 +9532,64 @@ 12 - 7 - 20 - 4 + 1 + 2 + 1211 - 21 - 54 - 4 + 2 + 3 + 1615 - 57 - 142 - 4 + 5 + 10 + 1211 - 146 - 236 - 4 + 11 + 13 + 1211 - 248 - 344 - 4 + 13 + 16 + 1211 - 509 - 620 - 4 + 17 + 36 + 1211 - 678 - 839 - 4 + 37 + 44 + 1211 - 1013 - 1235 - 4 + 49 + 120 + 1211 - 1272 - 2705 - 4 + 193 + 250 + 1211 - 3244 - 4582 - 4 + 322 + 516 + 1211 - 5616 - 10361 - 4 + 752 + 1581 + 1211 - 24892 - 237317 - 4 + 3202 + 12977 + 807 @@ -9481,64 +9603,64 @@ 12 - 7 - 20 - 4 + 1 + 2 + 1211 - 21 - 54 - 4 + 2 + 3 + 1615 - 57 - 142 - 4 + 5 + 10 + 1211 - 144 - 207 - 4 + 11 + 13 + 1211 - 233 - 324 - 4 + 13 + 16 + 1211 - 509 - 613 - 4 + 17 + 36 + 1211 - 676 - 790 - 4 + 37 + 39 + 1211 - 1013 - 1226 - 4 + 49 + 107 + 1211 - 1239 - 1949 - 4 + 119 + 177 + 1211 - 2582 - 3985 - 4 + 245 + 323 + 1211 - 4252 - 10115 - 4 + 414 + 1535 + 1211 - 14086 - 154744 - 4 + 2864 + 8533 + 807 @@ -9554,52 +9676,32 @@ 1 2 - 3 + 4441 2 3 - 8 + 4845 3 4 - 10 + 1615 4 - 5 - 6 - - - 5 - 7 - 4 - - - 7 - 8 - 4 - - - 8 - 14 - 3 - - - 15 - 22 - 4 + 11 + 1211 - 23 - 34 - 4 + 11 + 13 + 1211 - 1057 - 5164 - 2 + 14 + 638 + 1211 @@ -9615,22 +9717,22 @@ 1 2 - 65804 + 1170575 2 3 - 133334 + 2867283 3 - 5 - 17889 + 4 + 315760 - 5 - 5144 - 2297 + 4 + 637 + 163129 @@ -9646,17 +9748,17 @@ 1 2 - 137263 + 2711018 2 3 - 75813 + 1642197 3 - 7 - 6248 + 5 + 163533 @@ -9672,22 +9774,22 @@ 1 2 - 65804 + 1170575 2 3 - 133334 + 2867283 3 - 5 - 17889 + 4 + 315760 - 5 - 5144 - 2297 + 4 + 637 + 163129 @@ -9703,22 +9805,12 @@ 1 2 - 3910 + 249943 2 - 3 - 183 - - - 3 - 4 - 782 - - - 4 - 180006 - 288 + 9640 + 8075 @@ -9734,17 +9826,12 @@ 1 2 - 4087 + 250347 2 - 3 - 1033 - - - 3 - 48 - 43 + 33 + 7671 @@ -9760,22 +9847,12 @@ 1 2 - 3910 + 249943 2 - 3 - 183 - - - 3 - 4 - 782 - - - 4 - 180006 - 288 + 9640 + 8075 @@ -9785,19 +9862,19 @@ literals - 270756 + 8555361 expr - 270756 + 8555361 value - 25795 + 75495 raw - 27594 + 77891 @@ -9811,7 +9888,7 @@ 1 2 - 270756 + 8555361 @@ -9827,7 +9904,7 @@ 1 2 - 270756 + 8555361 @@ -9843,37 +9920,42 @@ 1 2 - 14635 + 27811 2 3 - 3291 + 12538 3 4 - 1783 + 6753 4 - 6 - 1931 + 5 + 5276 - 6 - 12 - 1968 + 5 + 8 + 6269 - 12 - 139 - 1935 + 8 + 17 + 5809 + + + 17 + 1233 + 5663 - 139 - 6840 - 252 + 1234 + 3959 + 5373 @@ -9889,12 +9971,12 @@ 1 2 - 24051 + 73171 2 - 5 - 1744 + 4 + 2323 @@ -9910,32 +9992,42 @@ 1 2 - 16038 + 29191 2 3 - 3521 + 13046 3 4 - 1869 + 6777 4 - 7 - 2553 + 5 + 5276 - 7 - 18 - 2129 + 5 + 8 + 6632 - 18 - 6833 - 1484 + 8 + 17 + 5857 + + + 17 + 1239 + 5857 + + + 1240 + 3937 + 5252 @@ -9951,7 +10043,7 @@ 1 2 - 27594 + 77891 @@ -9961,19 +10053,19 @@ constvalues - 43931 + 8093673 expr - 43931 + 8093673 value - 16896 + 27230 exact - 16897 + 27230 @@ -9987,7 +10079,7 @@ 1 2 - 43931 + 8093673 @@ -10003,7 +10095,7 @@ 1 2 - 43931 + 8093673 @@ -10019,17 +10111,37 @@ 1 2 - 14932 + 15539 2 - 4 - 1388 + 3 + 2420 - 4 - 6766 - 576 + 3 + 6 + 2130 + + + 6 + 1243 + 2105 + + + 1243 + 1281 + 2105 + + + 1281 + 1340 + 2057 + + + 1340 + 3974 + 871 @@ -10045,12 +10157,7 @@ 1 2 - 16895 - - - 2 - 3 - 1 + 27230 @@ -10066,17 +10173,37 @@ 1 2 - 14933 + 15539 2 - 4 - 1388 + 3 + 2420 - 4 - 6766 - 576 + 3 + 6 + 2130 + + + 6 + 1243 + 2105 + + + 1243 + 1281 + 2105 + + + 1281 + 1340 + 2057 + + + 1340 + 3974 + 871 @@ -10092,7 +10219,7 @@ 1 2 - 16897 + 27230 @@ -10102,19 +10229,19 @@ fields - 19974 + 995459 id - 19974 + 995459 parent - 9600 + 346065 idx - 57 + 48913 @@ -10128,7 +10255,7 @@ 1 2 - 19974 + 995459 @@ -10144,7 +10271,7 @@ 1 2 - 19974 + 995459 @@ -10160,27 +10287,32 @@ 1 2 - 4790 + 141898 2 3 - 2214 + 76625 3 4 - 1363 + 45908 4 5 - 653 + 32219 5 - 53 - 580 + 7 + 29548 + + + 7 + 290 + 19865 @@ -10196,27 +10328,32 @@ 1 2 - 4790 + 141898 2 3 - 2214 + 76625 3 4 - 1363 + 45908 4 5 - 653 + 32219 5 - 53 - 580 + 7 + 29548 + + + 7 + 290 + 19865 @@ -10232,47 +10369,27 @@ 1 2 - 14 + 38729 2 - 3 - 8 - - - 3 - 6 - 5 + 4 + 1836 - 6 - 11 - 5 + 4 + 12 + 3672 12 - 18 - 5 - - - 19 - 31 - 5 - - - 46 - 105 - 5 - - - 115 - 633 - 5 + 185 + 3672 - 914 - 7063 - 5 + 269 + 1368 + 1001 @@ -10288,47 +10405,27 @@ 1 2 - 14 + 38729 2 - 3 - 8 - - - 3 - 6 - 5 + 4 + 1836 - 6 - 11 - 5 + 4 + 12 + 3672 12 - 18 - 5 - - - 19 - 31 - 5 - - - 46 - 105 - 5 - - - 115 - 633 - 5 + 185 + 3672 - 914 - 7063 - 5 + 269 + 1368 + 1001 @@ -10337,30 +10434,26 @@ - stmts - 73990 + typeparamdecls + 9798 id - 73990 - - - kind - 33 + 9798 parent - 41543 + 8398 idx - 81 + 1399 id - kind + parent 12 @@ -10368,7 +10461,7 @@ 1 2 - 73990 + 9798 @@ -10376,7 +10469,7 @@ id - parent + idx 12 @@ -10384,15 +10477,15 @@ 1 2 - 73990 + 9798 - id - idx + parent + id 12 @@ -10400,85 +10493,61 @@ 1 2 - 73990 + 6999 + + + 2 + 3 + 1399 - kind - id + parent + idx 12 - 2 - 3 - 1 - - - 3 - 4 - 4 - - - 5 - 9 - 3 - - - 18 - 50 - 3 - - - 63 - 72 - 3 - - - 72 - 224 - 3 - - - 301 - 379 - 3 - - - 400 - 615 - 3 - - - 654 - 2136 - 3 + 1 + 2 + 6999 - 3476 - 7606 - 3 + 2 + 3 + 1399 + + + + + + idx + id + + + 12 + - 9225 - 9729 - 3 + 2 + 3 + 699 - 19358 - 19359 - 1 + 12 + 13 + 699 - kind + idx parent @@ -10487,62 +10556,185 @@ 2 3 - 1 + 699 - 3 + 12 + 13 + 699 + + + + + + + + + stmts + 1915917 + + + id + 1915917 + + + kind + 30538 + + + parent + 935456 + + + idx + 33753 + + + + + id + kind + + + 12 + + + 1 + 2 + 1915917 + + + + + + + id + parent + + + 12 + + + 1 + 2 + 1915917 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 1915917 + + + + + + + kind + id + + + 12 + + + 1 + 2 + 1607 + + + 3 4 - 4 + 1607 + + + 4 + 5 + 3214 5 + 6 + 1607 + + + 6 + 7 + 1607 + + + 7 + 8 + 1607 + + + 8 9 - 3 + 1607 - 17 - 35 - 3 + 11 + 12 + 1607 - 47 - 69 - 3 + 13 + 14 + 1607 - 69 - 205 - 3 + 14 + 15 + 1607 + + + 17 + 18 + 1607 + + + 33 + 34 + 1607 - 301 - 367 - 3 + 95 + 96 + 1607 - 385 - 586 - 3 + 106 + 107 + 1607 - 606 - 1154 - 3 + 177 + 178 + 1607 - 1719 - 5672 - 3 + 191 + 192 + 1607 - 5912 - 9226 - 3 + 208 + 209 + 1607 - 18820 - 18821 - 1 + 289 + 290 + 1607 @@ -10550,7 +10742,7 @@ kind - idx + parent 12 @@ -10558,70 +10750,95 @@ 1 2 - 1 + 1607 2 3 - 5 + 1607 3 + 4 + 1607 + + + 4 5 - 2 + 4821 5 - 8 - 3 + 6 + 1607 - 8 - 9 - 3 + 6 + 7 + 1607 - 9 + 7 + 8 + 1607 + + + 12 13 - 3 + 1607 13 - 16 - 3 + 14 + 1607 - 16 - 17 - 2 + 15 + 16 + 1607 17 - 27 - 3 + 18 + 1607 - 27 - 33 - 3 + 75 + 76 + 1607 - 44 - 47 - 3 + 88 + 89 + 1607 - 55 - 82 - 2 + 92 + 93 + 1607 + + + 106 + 107 + 1607 + + + 154 + 155 + 1607 + + + 274 + 275 + 1607 - parent - id + kind + idx 12 @@ -10629,22 +10846,57 @@ 1 2 - 29362 + 3214 2 3 - 6137 + 1607 3 + 4 + 9643 + + + 4 5 - 3650 + 3214 5 - 82 - 2394 + 6 + 1607 + + + 9 + 10 + 1607 + + + 12 + 13 + 1607 + + + 13 + 14 + 1607 + + + 15 + 16 + 3214 + + + 16 + 17 + 1607 + + + 20 + 21 + 1607 @@ -10652,7 +10904,7 @@ parent - kind + id 12 @@ -10660,22 +10912,22 @@ 1 2 - 31418 + 622030 2 3 - 5760 + 162338 3 5 - 3597 + 85187 5 - 11 - 768 + 22 + 65899 @@ -10683,7 +10935,7 @@ parent - idx + kind 12 @@ -10691,30 +10943,30 @@ 1 2 - 29362 + 683108 2 3 - 6137 + 155909 3 - 5 - 3650 + 6 + 72329 - 5 - 82 - 2394 + 6 + 8 + 24109 - idx - id + parent + idx 12 @@ -10722,52 +10974,22 @@ 1 2 - 6 + 622030 2 3 - 20 - - - 5 - 6 - 3 + 162338 - 7 - 8 - 11 - - - 10 - 15 - 7 - - - 15 - 27 - 7 - - - 27 - 70 - 7 - - - 85 - 262 - 7 - - - 314 - 1279 - 7 + 3 + 5 + 85187 - 1720 - 24879 - 6 + 5 + 22 + 65899 @@ -10775,7 +10997,7 @@ idx - kind + id 12 @@ -10783,52 +11005,87 @@ 1 2 - 12 + 1607 - 2 - 3 - 22 + 6 + 7 + 4821 - 3 - 5 - 7 - - - 5 - 6 - 6 + 7 + 8 + 3214 - 6 - 7 - 4 + 8 + 9 + 1607 - 7 - 9 - 7 + 10 + 11 + 1607 - 9 - 13 - 7 + 11 + 12 + 3214 - 13 + 17 18 - 7 + 1607 + + + 19 + 20 + 1607 20 - 28 - 6 + 21 + 1607 + + + 25 + 26 + 1607 29 - 34 - 3 + 30 + 1607 + + + 37 + 38 + 1607 + + + 41 + 42 + 1607 + + + 98 + 99 + 1607 + + + 167 + 168 + 1607 + + + 331 + 332 + 1607 + + + 335 + 336 + 1607 @@ -10836,7 +11093,7 @@ idx - parent + kind 12 @@ -10844,52 +11101,163 @@ 1 2 - 6 + 3214 2 3 - 20 + 1607 + + + 3 + 4 + 3214 + + + 4 + 5 + 4821 5 6 - 3 + 4821 + + + 6 + 7 + 1607 7 8 - 11 + 3214 + + + 8 + 9 + 1607 + + + 9 + 10 + 3214 10 + 11 + 1607 + + + 12 + 13 + 1607 + + + 14 15 - 7 + 1607 - 15 - 27 - 7 + 16 + 17 + 1607 + + + + + + idx + parent + + + 12 + - 27 - 70 - 7 + 1 + 2 + 1607 - 85 - 262 - 7 + 6 + 7 + 4821 + + + 7 + 8 + 3214 + + + 8 + 9 + 1607 + + + 10 + 11 + 1607 + + + 11 + 12 + 3214 + + + 17 + 18 + 1607 + + + 19 + 20 + 1607 + + + 20 + 21 + 1607 + + + 25 + 26 + 1607 + + + 29 + 30 + 1607 + + + 37 + 38 + 1607 + + + 41 + 42 + 1607 + + + 98 + 99 + 1607 + + + 167 + 168 + 1607 - 314 - 1279 - 7 + 331 + 332 + 1607 - 1720 - 24879 - 6 + 335 + 336 + 1607 @@ -10899,23 +11267,23 @@ decls - 8690 + 443378 id - 8690 + 443378 kind - 5 + 528 parent - 1951 + 123356 idx - 226 + 59475 @@ -10929,7 +11297,7 @@ 1 2 - 8690 + 443378 @@ -10945,7 +11313,7 @@ 1 2 - 8690 + 443378 @@ -10961,7 +11329,7 @@ 1 2 - 8690 + 443378 @@ -10975,29 +11343,34 @@ 12 - 280 - 281 - 1 + 2 + 3 + 88 + + + 45 + 46 + 88 - 479 - 480 - 1 + 208 + 209 + 88 - 1349 - 1350 - 1 + 421 + 422 + 88 - 1769 - 1770 - 1 + 1140 + 1141 + 88 - 4813 - 4814 - 1 + 3216 + 3217 + 88 @@ -11011,29 +11384,34 @@ 12 - 196 - 197 - 1 + 2 + 3 + 88 + + + 34 + 35 + 88 - 336 - 337 - 1 + 100 + 101 + 88 - 478 - 479 - 1 + 421 + 422 + 88 - 483 - 484 - 1 + 547 + 548 + 88 - 1566 - 1567 - 1 + 882 + 883 + 88 @@ -11047,29 +11425,29 @@ 12 - 2 - 3 - 1 + 1 + 2 + 176 - 39 - 40 - 1 + 15 + 16 + 88 - 105 - 106 - 1 + 26 + 27 + 88 - 219 - 220 - 1 + 237 + 238 + 88 - 225 - 226 - 1 + 675 + 676 + 88 @@ -11085,27 +11463,27 @@ 1 2 - 1460 + 80886 2 - 6 - 149 + 3 + 16476 - 6 - 12 - 155 + 3 + 5 + 9956 - 12 - 36 - 147 + 5 + 12 + 9956 - 36 - 227 - 40 + 12 + 676 + 6079 @@ -11121,27 +11499,17 @@ 1 2 - 1463 + 83089 2 3 - 111 + 31632 3 - 4 - 185 - - - 4 - 5 - 141 - - - 5 6 - 51 + 8634 @@ -11157,27 +11525,27 @@ 1 2 - 1460 + 80886 2 - 6 - 149 + 3 + 16476 - 6 - 12 - 155 + 3 + 5 + 9956 - 12 - 36 - 147 + 5 + 12 + 9956 - 36 - 227 - 40 + 12 + 676 + 6079 @@ -11193,57 +11561,22 @@ 1 2 - 4 + 38592 2 3 - 30 + 13833 3 - 4 - 18 - - - 4 - 5 - 66 - - - 5 - 6 - 2 - - - 6 - 7 - 31 - - - 7 - 11 - 17 - - - 11 - 31 - 17 - - - 31 - 65 - 17 - - - 67 - 275 - 17 + 17 + 4581 - 323 - 1952 - 7 + 19 + 1401 + 2467 @@ -11259,27 +11592,17 @@ 1 2 - 7 + 38592 2 3 - 113 + 18503 3 - 4 - 69 - - - 4 - 5 - 35 - - - 5 - 6 - 2 + 7 + 2379 @@ -11295,57 +11618,22 @@ 1 2 - 4 + 38592 2 3 - 30 + 13833 3 - 4 - 18 + 17 + 4581 - 4 - 5 - 66 - - - 5 - 6 - 2 - - - 6 - 7 - 31 - - - 7 - 11 - 17 - - - 11 - 31 - 17 - - - 31 - 65 - 17 - - - 67 - 275 - 17 - - - 323 - 1952 - 7 + 19 + 1401 + 2467 @@ -11355,23 +11643,23 @@ specs - 7889 + 397829 id - 7889 + 397829 kind - 4 + 5234 parent - 3877 + 193680 idx - 108 + 31407 @@ -11385,7 +11673,7 @@ 1 2 - 7889 + 397829 @@ -11401,7 +11689,7 @@ 1 2 - 7889 + 397829 @@ -11417,7 +11705,7 @@ 1 2 - 7889 + 397829 @@ -11431,24 +11719,19 @@ 12 - 16 - 17 - 1 - - - 1349 - 1350 - 1 + 18 + 19 + 1744 - 3056 - 3057 - 1 + 70 + 71 + 1744 - 3468 - 3469 - 1 + 140 + 141 + 1744 @@ -11462,24 +11745,19 @@ 12 - 16 - 17 - 1 - - - 479 - 480 - 1 + 18 + 19 + 1744 - 1333 - 1334 - 1 + 23 + 24 + 1744 - 2049 - 2050 - 1 + 70 + 71 + 1744 @@ -11495,22 +11773,12 @@ 1 2 - 1 + 3489 - 14 - 15 - 1 - - - 36 - 37 - 1 - - - 108 - 109 - 1 + 18 + 19 + 1744 @@ -11526,22 +11794,22 @@ 1 2 - 3206 + 157037 2 - 6 - 343 + 5 + 15703 6 - 18 - 298 + 11 + 15703 - 18 - 109 - 30 + 14 + 19 + 5234 @@ -11557,7 +11825,7 @@ 1 2 - 3877 + 193680 @@ -11573,22 +11841,22 @@ 1 2 - 3206 + 157037 2 - 6 - 343 + 5 + 15703 6 - 18 - 298 + 11 + 15703 - 18 - 109 - 30 + 14 + 19 + 5234 @@ -11604,32 +11872,47 @@ 1 2 - 53 + 6979 - 2 - 3 - 19 + 3 + 4 + 6979 - 3 - 6 - 9 + 4 + 5 + 3489 - 6 - 28 - 9 + 9 + 10 + 3489 - 30 - 156 - 9 + 12 + 13 + 3489 + + + 14 + 15 + 1744 + + + 16 + 17 + 1744 + + + 21 + 22 + 1744 - 188 - 3878 - 9 + 111 + 112 + 1744 @@ -11645,22 +11928,12 @@ 1 2 - 72 - - - 2 - 3 - 22 + 29662 3 4 - 13 - - - 4 - 5 - 1 + 1744 @@ -11676,32 +11949,47 @@ 1 2 - 53 + 6979 - 2 - 3 - 19 + 3 + 4 + 6979 - 3 - 6 - 9 + 4 + 5 + 3489 - 6 - 28 - 9 + 9 + 10 + 3489 - 30 - 156 - 9 + 12 + 13 + 3489 + + + 14 + 15 + 1744 + + + 16 + 17 + 1744 + + + 21 + 22 + 1744 - 188 - 3878 - 9 + 111 + 112 + 1744 @@ -11711,15 +11999,15 @@ scopes - 36775 + 1519778 id - 36775 + 1519778 kind - 3 + 5234 @@ -11733,7 +12021,7 @@ 1 2 - 36775 + 1519778 @@ -11749,17 +12037,17 @@ 1 2 - 1 + 1744 - 346 - 347 - 1 + 340 + 341 + 1744 - 36428 - 36429 - 1 + 530 + 531 + 1744 @@ -11769,15 +12057,15 @@ scopenesting - 36774 + 1518033 inner - 36774 + 1518033 outer - 21713 + 397829 @@ -11791,7 +12079,7 @@ 1 2 - 36774 + 1518033 @@ -11807,22 +12095,22 @@ 1 2 - 16964 + 280923 2 3 - 2474 + 71539 3 - 7 - 1759 + 5 + 34897 - 7 - 347 - 516 + 5 + 531 + 10469 @@ -11832,15 +12120,15 @@ scopenodes - 36428 + 919952 node - 36428 + 919952 scope - 36428 + 919952 @@ -11854,7 +12142,7 @@ 1 2 - 36428 + 919952 @@ -11870,7 +12158,7 @@ 1 2 - 36428 + 919952 @@ -11880,19 +12168,19 @@ objects - 84909 + 260849313 id - 84909 + 260849313 kind - 9 + 32863 name - 30576 + 153297959 @@ -11906,7 +12194,7 @@ 1 2 - 84909 + 260849313 @@ -11922,7 +12210,7 @@ 1 2 - 84909 + 260849313 @@ -11938,47 +12226,42 @@ 4 5 - 1 - - - 18 - 19 - 1 + 4107 - 20 - 21 - 1 + 22 + 23 + 4107 - 49 - 50 - 1 + 26 + 27 + 4107 - 3468 - 3469 - 1 + 33 + 34 + 4107 - 3602 - 3603 - 1 + 3147 + 3148 + 4107 - 8857 - 8858 - 1 + 17646 + 17647 + 4107 - 17793 - 17794 - 1 + 19579 + 19580 + 4107 - 51098 - 51099 - 1 + 23041 + 23042 + 4107 @@ -11994,47 +12277,42 @@ 4 5 - 1 - - - 18 - 19 - 1 + 4107 - 20 - 21 - 1 + 22 + 23 + 4107 - 38 - 39 - 1 + 23 + 24 + 4107 - 203 - 204 - 1 + 26 + 27 + 4107 - 3004 - 3005 - 1 + 2654 + 2655 + 4107 - 8418 - 8419 - 1 + 7829 + 7830 + 4107 - 10132 - 10133 - 1 + 10951 + 10952 + 4107 - 10913 - 10914 - 1 + 17127 + 17128 + 4107 @@ -12050,22 +12328,17 @@ 1 2 - 25286 + 124595415 2 3 - 2613 + 20954870 3 - 20 - 2304 - - - 20 - 2222 - 373 + 1189 + 7747674 @@ -12081,12 +12354,12 @@ 1 2 - 28809 + 148692899 2 6 - 1767 + 4605059 @@ -12096,15 +12369,15 @@ objectscopes - 54774 + 140464590 object - 54774 + 140464590 scope - 13947 + 1068078 @@ -12118,7 +12391,7 @@ 1 2 - 54774 + 140464590 @@ -12134,32 +12407,72 @@ 1 2 - 7112 + 73943 2 3 - 2972 + 57511 3 4 - 1274 + 69835 4 - 6 - 1264 + 7 + 86267 - 6 - 15 - 1055 + 7 + 13 + 82159 - 15 - 2694 - 270 + 13 + 18 + 86267 + + + 18 + 24 + 86267 + + + 24 + 35 + 86267 + + + 35 + 48 + 82159 + + + 48 + 62 + 82159 + + + 63 + 106 + 82159 + + + 108 + 186 + 82159 + + + 206 + 689 + 82159 + + + 711 + 10035 + 28755 @@ -12169,15 +12482,15 @@ objecttypes - 84907 + 258988392 object - 84907 + 258988392 tp - 13462 + 47738981 @@ -12191,7 +12504,7 @@ 1 2 - 84907 + 258988392 @@ -12207,32 +12520,32 @@ 1 2 - 7893 + 29216043 2 3 - 2114 + 7813401 3 4 - 892 + 3039914 4 7 - 1190 + 3730057 7 - 25 - 1011 + 53 + 3582169 - 25 - 4267 - 362 + 53 + 13253 + 357395 @@ -12242,15 +12555,15 @@ methodreceivers - 9873 + 70035448 method - 9873 + 70035448 receiver - 9873 + 70035448 @@ -12264,7 +12577,7 @@ 1 2 - 9873 + 70035448 @@ -12280,7 +12593,7 @@ 1 2 - 9873 + 70035448 @@ -12290,15 +12603,15 @@ fieldstructs - 10934 + 41038845 field - 10934 + 41038845 struct - 2408 + 8035233 @@ -12312,7 +12625,7 @@ 1 2 - 10934 + 41038845 @@ -12328,42 +12641,42 @@ 1 2 - 260 + 936622 2 3 - 677 + 2033456 3 4 - 468 + 1425473 4 5 - 292 + 1031106 5 6 - 194 + 640846 6 8 - 208 + 694250 8 - 13 - 199 + 12 + 681926 - 13 - 65 - 110 + 12 + 80 + 591550 @@ -12373,15 +12686,15 @@ methodhosts - 838 + 8181678 method - 699 + 5569613 host - 258 + 1579104 @@ -12395,17 +12708,27 @@ 1 2 - 625 + 4430215 2 3 - 56 + 509500 3 - 16 - 18 + 4 + 122140 + + + 4 + 5 + 439706 + + + 5 + 28 + 68049 @@ -12421,55 +12744,60 @@ 1 2 - 99 + 645600 2 3 - 56 + 272199 3 4 - 37 + 158782 4 5 - 20 + 90733 5 - 6 - 15 + 8 + 130864 - 6 + 8 11 - 21 + 123885 11 - 53 - 10 + 19 + 118650 - - - + + 19 + 293 + 38387 + + + + defs - 40703 + 1417649 ident - 40703 + 1417649 object - 40490 + 1388768 @@ -12483,7 +12811,7 @@ 1 2 - 40703 + 1417649 @@ -12499,12 +12827,12 @@ 1 2 - 40383 + 1370071 2 - 15 - 107 + 7 + 18697 @@ -12514,15 +12842,15 @@ uses - 195902 + 4531459 ident - 195902 + 4531459 object - 41616 + 802598 @@ -12536,7 +12864,7 @@ 1 2 - 195902 + 4531459 @@ -12552,37 +12880,37 @@ 1 2 - 15493 + 294651 2 3 - 9727 + 231900 3 4 - 5056 + 77848 4 5 - 2974 + 50873 5 - 7 - 3203 + 8 + 68403 - 7 - 14 - 3336 + 8 + 21 + 60890 - 14 - 6833 - 1827 + 21 + 3870 + 18031 @@ -12592,15 +12920,15 @@ types - 18132 + 64230277 id - 18132 + 64230277 kind - 37 + 68049 @@ -12614,7 +12942,7 @@ 1 2 - 18132 + 64230277 @@ -12630,27 +12958,32 @@ 1 2 - 25 + 41876 - 10 - 30 - 3 + 12 + 25 + 5234 + + + 34 + 143 + 5234 - 247 - 431 - 3 + 158 + 413 + 5234 - 559 - 1904 - 3 + 938 + 4626 + 5234 - 2409 - 8011 - 3 + 4676 + 16593 + 5234 @@ -12660,15 +12993,15 @@ type_of - 397965 + 8829217 expr - 397965 + 8829217 tp - 8687 + 26916 @@ -12682,7 +13015,7 @@ 1 2 - 397965 + 8829217 @@ -12698,57 +13031,52 @@ 1 2 - 2019 + 4744 2 3 - 967 + 5567 3 4 - 711 + 2154 4 5 - 388 + 2444 5 7 - 780 + 2420 7 10 - 772 + 2105 10 15 - 734 + 2033 15 - 23 - 700 - - - 23 - 43 - 652 + 26 + 2105 - 43 - 143 - 652 + 26 + 90 + 2081 - 143 - 46949 - 312 + 90 + 331257 + 1258 @@ -12758,15 +13086,15 @@ typename - 3567 + 13128374 tp - 3567 + 13128374 name - 2983 + 10010298 @@ -12780,7 +13108,7 @@ 1 2 - 3567 + 13128374 @@ -12796,17 +13124,17 @@ 1 2 - 2660 + 8108394 2 - 4 - 267 + 3 + 1210937 - 4 - 17 - 56 + 3 + 26 + 690967 @@ -12816,15 +13144,15 @@ key_type - 430 + 866786 map - 430 + 866786 tp - 149 + 283451 @@ -12838,7 +13166,7 @@ 1 2 - 430 + 866786 @@ -12854,27 +13182,27 @@ 1 2 - 106 + 201291 2 3 - 17 + 28755 3 6 - 12 + 24647 - 6 + 9 13 - 12 + 24647 - 20 - 136 - 2 + 65 + 66 + 4107 @@ -12884,15 +13212,15 @@ element_type - 1412 + 4132640 container - 1412 + 4132640 tp - 916 + 2382635 @@ -12906,7 +13234,7 @@ 1 2 - 1412 + 4132640 @@ -12922,17 +13250,17 @@ 1 2 - 773 + 2008808 2 3 - 94 + 250587 3 - 68 - 49 + 78 + 123239 @@ -12942,15 +13270,15 @@ base_type - 1903 + 8158995 ptr - 1903 + 8158995 tp - 1903 + 8158995 @@ -12964,7 +13292,7 @@ 1 2 - 1903 + 8158995 @@ -12980,7 +13308,7 @@ 1 2 - 1903 + 8158995 @@ -12990,15 +13318,15 @@ underlying_type - 3567 + 12852686 named - 3567 + 12852686 tp - 2755 + 9731120 @@ -13012,7 +13340,7 @@ 1 2 - 3567 + 12852686 @@ -13028,12 +13356,75 @@ 1 2 - 2582 + 8959889 + + + 2 + 9 + 732843 + + + 9 + 252 + 38387 + + + + + + + + + alias_rhs + 660784 + + + alias + 660784 + + + tp + 320067 + + + + + alias + tp + + + 12 + + + 1 + 2 + 660784 + + + + + + + tp + alias + + + 12 + + + 1 + 2 + 284886 2 - 154 - 173 + 4 + 28679 + + + 4 + 348 + 6500 @@ -13043,23 +13434,23 @@ component_types - 36474 + 130391792 parent - 11221 + 37395056 index - 74 + 361503 name - 5540 + 21435505 tp - 4295 + 15006496 @@ -13073,37 +13464,37 @@ 1 2 - 1198 + 4761163 2 3 - 3864 + 10956016 3 4 - 2953 + 9378547 4 5 - 1446 + 5356822 5 6 - 780 + 3076886 6 - 13 - 860 + 11 + 2982402 - 13 - 65 - 120 + 11 + 80 + 883218 @@ -13119,22 +13510,27 @@ 1 2 - 8936 + 29495386 2 3 - 733 + 2230639 3 - 6 - 1008 + 5 + 2768787 - 6 - 64 - 544 + 5 + 39 + 2805758 + + + 39 + 80 + 94483 @@ -13150,32 +13546,32 @@ 1 2 - 2194 + 6646732 2 3 - 4537 + 13724803 3 4 - 2475 + 9657890 4 5 - 1110 + 4284636 5 12 - 848 + 2818082 12 - 52 - 57 + 34 + 262911 @@ -13191,62 +13587,62 @@ 1 2 - 15 + 65727 2 - 4 - 6 + 3 + 32863 - 4 - 7 - 4 + 3 + 5 + 28755 - 8 - 13 - 6 + 5 + 11 + 28755 - 13 - 18 - 6 + 12 + 23 + 28755 - 18 - 28 - 6 + 23 + 31 + 28755 - 29 - 49 - 6 + 34 + 50 + 28755 - 52 - 82 - 6 + 51 + 75 + 28755 - 89 - 193 - 6 + 79 + 149 + 28755 - 232 - 824 - 6 + 169 + 511 + 28755 - 1505 - 6458 - 6 + 778 + 5506 + 28755 - 10274 - 10275 - 1 + 8121 + 8122 + 4107 @@ -13262,52 +13658,52 @@ 1 2 - 22 + 94483 2 - 6 - 6 + 3 + 32863 - 6 - 9 - 6 + 4 + 6 + 28755 - 9 - 16 - 4 + 6 + 14 + 32863 - 16 - 24 - 6 + 17 + 22 + 28755 - 24 - 37 - 6 + 22 + 34 + 28755 - 39 - 61 - 6 + 35 + 55 + 28755 - 69 - 116 - 6 + 58 + 102 + 28755 - 153 - 379 - 6 + 110 + 277 + 28755 - 475 - 1260 - 6 + 331 + 1018 + 28755 @@ -13323,62 +13719,62 @@ 1 2 - 15 + 65727 2 - 4 - 6 + 3 + 32863 - 4 - 7 - 6 + 3 + 5 + 32863 - 7 - 11 - 5 + 5 + 7 + 24647 - 11 - 14 - 5 + 9 + 15 + 28755 15 19 - 6 + 28755 20 - 27 - 5 + 25 + 28755 - 29 - 44 - 6 + 25 + 37 + 28755 - 45 - 72 - 6 + 38 + 59 + 28755 - 86 - 161 - 6 + 67 + 149 + 28755 - 224 - 1436 - 6 + 179 + 1225 + 28755 - 1878 - 2153 - 2 + 1559 + 1560 + 4107 @@ -13394,22 +13790,22 @@ 1 2 - 3941 + 13843935 2 3 - 851 + 4633815 3 - 6 - 484 + 5 + 1733572 - 6 - 8917 - 264 + 5 + 7182 + 1224181 @@ -13425,22 +13821,22 @@ 1 2 - 4284 + 16793473 2 3 - 737 + 2998834 3 - 6 - 440 + 12 + 1618549 - 6 - 28 - 79 + 12 + 31 + 24647 @@ -13456,22 +13852,17 @@ 1 2 - 4599 + 18029979 2 3 - 518 + 2099184 3 - 21 - 416 - - - 21 - 3014 - 7 + 2295 + 1306341 @@ -13487,32 +13878,32 @@ 1 2 - 2055 + 7665514 2 3 - 812 + 2748247 3 4 - 408 + 1207749 4 6 - 394 + 1277585 6 - 11 - 342 + 12 + 1199533 - 11 - 2187 - 284 + 12 + 2060 + 907866 @@ -13528,32 +13919,27 @@ 1 2 - 2111 + 8893803 2 3 - 859 + 2863270 3 4 - 580 + 1409041 4 - 5 - 352 - - - 5 - 10 - 328 + 6 + 1146129 - 10 - 51 - 65 + 6 + 68 + 694250 @@ -13569,22 +13955,22 @@ 1 2 - 2897 + 11165523 2 3 - 865 + 2193668 3 - 5 - 343 + 6 + 1187209 - 5 - 738 - 190 + 6 + 719 + 460095 @@ -13593,38 +13979,26 @@ - array_length - 293 + component_tags + 41038845 - tp - 293 + parent + 8035233 - len - 103 + index + 324531 + + + tag + 747654 - tp - len - - - 12 - - - 1 - 2 - 293 - - - - - - - len - tp + parent + index 12 @@ -13632,56 +14006,50 @@ 1 2 - 62 + 936622 2 3 - 15 + 2033456 3 4 - 7 + 1425473 4 - 7 - 8 + 5 + 1031106 - 7 - 15 - 7 + 5 + 6 + 640846 - 15 - 26 - 4 + 6 + 8 + 694250 + + + 8 + 12 + 681926 + + + 12 + 80 + 591550 - - - - type_objects - 3567 - - - tp - 3567 - - - object - 3567 - - - - tp - object + parent + tag 12 @@ -13689,15 +14057,20 @@ 1 2 - 3567 + 7891453 + + + 2 + 36 + 143779 - object - tp + index + parent 12 @@ -13705,39 +14078,70 @@ 1 2 - 3567 + 57511 + + + 2 + 3 + 32863 + + + 4 + 5 + 24647 + + + 6 + 11 + 24647 + + + 12 + 22 + 24647 + + + 22 + 25 + 24647 + + + 26 + 36 + 24647 + + + 39 + 55 + 24647 + + + 58 + 93 + 24647 + + + 105 + 220 + 24647 + + + 252 + 887 + 24647 + + + 1233 + 1957 + 12323 - - - - packages - 346 - - - id - 346 - - - name - 281 - - - path - 346 - - - scope - 346 - - - - id - name + index + tag 12 @@ -13745,15 +14149,35 @@ 1 2 - 346 + 180751 + + + 2 + 3 + 73943 + + + 3 + 7 + 24647 + + + 9 + 15 + 24647 + + + 15 + 29 + 20539 - id - path + tag + parent 12 @@ -13761,15 +14185,25 @@ 1 2 - 346 + 673710 + + + 2 + 4 + 61619 + + + 4 + 1931 + 12323 - id - scope + tag + index 12 @@ -13777,15 +14211,40 @@ 1 2 - 346 + 690142 + + + 2 + 80 + 57511 + + + + interface_private_method_ids + 439555 + + + interface + 156103 + + + index + 94483 + + + id + 386151 + + + - name - id + interface + index 12 @@ -13793,25 +14252,45 @@ 1 2 - 255 + 53403 2 3 - 23 + 53403 3 - 40 - 3 + 4 + 12323 + + + 4 + 5 + 8215 + + + 5 + 6 + 12323 + + + 7 + 10 + 12323 + + + 12 + 13 + 4107 - name - path + interface + id 12 @@ -13819,25 +14298,45 @@ 1 2 - 255 + 53403 2 3 - 23 + 53403 3 - 40 - 3 + 4 + 12323 + + + 4 + 5 + 8215 + + + 5 + 6 + 12323 + + + 7 + 10 + 12323 + + + 12 + 13 + 4107 - name - scope + index + interface 12 @@ -13845,24 +14344,39 @@ 1 2 - 255 + 24647 2 3 - 23 + 28755 3 - 40 - 3 + 4 + 16431 + + + 5 + 10 + 8215 + + + 10 + 14 + 8215 + + + 18 + 21 + 8215 - path + index id @@ -13871,31 +14385,40 @@ 1 2 - 346 + 32863 - - - - - - path - name - - - 12 - - 1 - 2 - 346 + 2 + 3 + 28755 + + + 3 + 4 + 8215 + + + 5 + 10 + 8215 + + + 10 + 14 + 8215 + + + 18 + 21 + 8215 - path - scope + id + interface 12 @@ -13903,15 +14426,25 @@ 1 2 - 346 + 345071 + + + 2 + 3 + 28755 + + + 3 + 4 + 12323 - scope - id + id + index 12 @@ -13919,15 +14452,36 @@ 1 2 - 346 + 361503 + + + 2 + 4 + 24647 - - scope - name + + + + array_length + 1528173 + + + tp + 1528173 + + + len + 488851 + + + + + tp + len 12 @@ -13935,15 +14489,15 @@ 1 2 - 346 + 1528173 - scope - path + len + tp 12 @@ -13951,7 +14505,37 @@ 1 2 - 346 + 258803 + + + 2 + 3 + 90375 + + + 3 + 4 + 24647 + + + 4 + 5 + 24647 + + + 5 + 7 + 41079 + + + 8 + 15 + 36971 + + + 16 + 28 + 12323 @@ -13960,30 +14544,78 @@ - modexprs - 9 + type_objects + 13128374 + + + tp + 13128374 + + + object + 13128374 + + + + + tp + object + + + 12 + + + 1 + 2 + 13128374 + + + + + + + object + tp + + + 12 + + + 1 + 2 + 13128374 + + + + + + + + + packages + 924779 id - 9 + 924779 - kind - 4 + name + 570571 - parent - 2 + path + 924779 - idx - 6 + scope + 924779 id - kind + name 12 @@ -13991,7 +14623,7 @@ 1 2 - 9 + 924779 @@ -13999,7 +14631,7 @@ id - parent + path 12 @@ -14007,7 +14639,7 @@ 1 2 - 9 + 924779 @@ -14015,7 +14647,7 @@ id - idx + scope 12 @@ -14023,14 +14655,14 @@ 1 2 - 9 + 924779 - kind + name id @@ -14039,20 +14671,25 @@ 1 2 - 3 + 479838 - 6 - 7 - 1 + 2 + 3 + 57580 + + + 3 + 53 + 33152 - kind - parent + name + path 12 @@ -14060,20 +14697,25 @@ 1 2 - 3 + 479838 2 3 - 1 + 57580 + + + 3 + 53 + 33152 - kind - idx + name + scope 12 @@ -14081,82 +14723,72 @@ 1 2 - 3 + 479838 - 5 - 6 - 1 + 2 + 3 + 57580 + + + 3 + 53 + 33152 - parent + path id 12 - 3 - 4 - 1 - - - 6 - 7 - 1 + 1 + 2 + 924779 - parent - kind + path + name 12 - 2 - 3 - 1 - - - 3 - 4 - 1 + 1 + 2 + 924779 - parent - idx + path + scope 12 - 3 - 4 - 1 - - - 6 - 7 - 1 + 1 + 2 + 924779 - idx + scope id @@ -14165,20 +14797,15 @@ 1 2 - 3 - - - 2 - 3 - 3 + 924779 - idx - kind + scope + name 12 @@ -14186,20 +14813,15 @@ 1 2 - 4 - - - 2 - 3 - 2 + 924779 - idx - parent + scope + path 12 @@ -14207,12 +14829,7 @@ 1 2 - 3 - - - 2 - 3 - 3 + 924779 @@ -14221,26 +14838,30 @@ - modtokens - 13 + modexprs + 259985 - token - 13 + id + 259985 + + + kind + 6979 parent - 7 + 54090 idx - 2 + 24428 - token - parent + id + kind 12 @@ -14248,15 +14869,15 @@ 1 2 - 13 + 259985 - token - idx + id + parent 12 @@ -14264,15 +14885,15 @@ 1 2 - 13 + 259985 - parent - token + id + idx 12 @@ -14280,143 +14901,134 @@ 1 2 - 1 - - - 2 - 3 - 6 + 259985 - parent - idx + kind + id 12 - 1 - 2 - 1 + 13 + 14 + 5234 - 2 - 3 - 6 + 110 + 111 + 1744 - idx - token + kind + parent 12 - 6 - 7 - 1 + 12 + 13 + 1744 - 7 - 8 - 1 + 13 + 14 + 3489 + + + 31 + 32 + 1744 - idx - parent + kind + idx 12 - 6 - 7 - 1 + 1 + 2 + 1744 - 7 - 8 - 1 + 2 + 3 + 1744 + + + 5 + 6 + 1744 + + + 13 + 14 + 1744 - - - - errors - 0 - - - id - 0 - - - kind - 0 - - - msg - 0 - - - rawpos - 0 - - - file - 0 - - - line - 0 - - - col - 0 - - - package - 0 - - - idx - 0 - - - - id - kind + parent + id 12 - 1 - 2 - 1 + 2 + 3 + 8724 + + + 3 + 4 + 19193 + + + 4 + 5 + 6979 + + + 5 + 6 + 10469 + + + 11 + 12 + 5234 + + + 13 + 15 + 3489 - id - msg + parent + kind 12 @@ -14424,31 +15036,66 @@ 1 2 - 1 + 10469 + + + 2 + 3 + 20938 + + + 3 + 4 + 22683 - id - rawpos + parent + idx 12 - 1 - 2 - 1 + 2 + 3 + 8724 + + + 3 + 4 + 19193 + + + 4 + 5 + 6979 + + + 5 + 6 + 10469 + + + 11 + 12 + 5234 + + + 13 + 15 + 3489 - id - file + idx + id 12 @@ -14456,15 +15103,45 @@ 1 2 - 1 + 1744 + + + 2 + 3 + 3489 + + + 5 + 6 + 10469 + + + 11 + 12 + 1744 + + + 15 + 16 + 1744 + + + 26 + 27 + 1744 + + + 31 + 32 + 3489 - id - line + idx + kind 12 @@ -14472,15 +15149,25 @@ 1 2 - 1 + 13958 + + + 2 + 3 + 8724 + + + 3 + 4 + 1744 - id - col + idx + parent 12 @@ -14488,15 +15175,65 @@ 1 2 - 1 + 1744 + + + 2 + 3 + 3489 + + + 5 + 6 + 10469 + + + 11 + 12 + 1744 + + + 15 + 16 + 1744 + + + 26 + 27 + 1744 + + + 31 + 32 + 3489 + + + + modtokens + 410043 + + + token + 164017 + + + parent + 214618 + + + idx + 5234 + + + - id - package + token + parent 12 @@ -14504,14 +15241,34 @@ 1 2 - 1 + 76774 + + + 2 + 3 + 54090 + + + 3 + 5 + 13958 + + + 5 + 9 + 13958 + + + 15 + 19 + 5234 - id + token idx @@ -14520,664 +15277,3123 @@ 1 2 - 1 + 162272 + + + 2 + 3 + 1744 - kind - id - - - 12 - - - - - - kind - msg + parent + token 12 - - - - - - kind - rawpos - - - 12 - - - - - - kind - file - - - 12 - - - - - - kind - line - - - 12 - + + + 1 + 2 + 22683 + + + 2 + 3 + 188445 + + + 3 + 4 + 3489 + + - kind - col + parent + idx 12 - + + + 1 + 2 + 22683 + + + 2 + 3 + 188445 + + + 3 + 4 + 3489 + + - kind - package + idx + token 12 - + + + 2 + 3 + 1744 + + + 40 + 41 + 1744 + + + 53 + 54 + 1744 + + - kind - idx + idx + parent 12 - + + + 2 + 3 + 1744 + + + 110 + 111 + 1744 + + + 123 + 124 + 1744 + + + + + + errors + 232496 + + + id + 232496 + + + kind + 642 + + + msg + 55713 + + + rawpos + 155997 + + + file + 56356 + + + line + 21856 + + + col + 10071 + + + package + 16928 + + + idx + 89355 + + + - msg - id + id + kind 12 - + + + 1 + 2 + 232496 + + - msg - kind + id + msg 12 - + + + 1 + 2 + 232496 + + - msg + id rawpos 12 - + + + 1 + 2 + 232496 + + - msg + id file 12 - + + + 1 + 2 + 232496 + + - msg + id line 12 - + + + 1 + 2 + 232496 + + - msg + id col 12 - + + + 1 + 2 + 232496 + + - msg + id package 12 - + + + 1 + 2 + 232496 + + - msg + id idx 12 - + + + 1 + 2 + 232496 + + - rawpos + kind id 12 - + + + 16 + 17 + 214 + + + 45 + 46 + 214 + + + 1024 + 1025 + 214 + + - rawpos - kind + kind + msg 12 - + + + 10 + 11 + 214 + + + 41 + 42 + 214 + + + 210 + 211 + 214 + + - rawpos - msg + kind + rawpos 12 - - - - + + + 9 + 10 + 214 + + + 39 + 40 + 214 + + + 680 + 681 + 214 + + + + + - rawpos + kind file 12 - + + + 4 + 5 + 214 + + + 26 + 27 + 214 + + + 262 + 263 + 214 + + - rawpos + kind line 12 - + + + 6 + 7 + 214 + + + 16 + 17 + 214 + + + 102 + 103 + 214 + + - rawpos + kind col 12 - + + + 6 + 7 + 214 + + + 8 + 9 + 214 + + + 42 + 43 + 214 + + - rawpos + kind package 12 - + + + 3 + 4 + 214 + + + 36 + 37 + 214 + + + 45 + 46 + 214 + + - rawpos + kind idx 12 - + + + 1 + 2 + 214 + + + 13 + 14 + 214 + + + 417 + 418 + 214 + + - file + msg id 12 - + + + 1 + 2 + 30856 + + + 2 + 3 + 8357 + + + 3 + 4 + 6428 + + + 4 + 7 + 4928 + + + 7 + 17 + 4285 + + + 20 + 214 + 857 + + - file + msg kind 12 - + + + 1 + 2 + 55499 + + + 2 + 3 + 214 + + - file - msg + msg + rawpos 12 - + + + 1 + 2 + 38142 + + + 2 + 3 + 6428 + + + 3 + 4 + 4071 + + + 4 + 8 + 4499 + + + 8 + 214 + 2571 + + - file - rawpos + msg + file 12 - + + + 1 + 2 + 39642 + + + 2 + 3 + 6857 + + + 3 + 5 + 4499 + + + 5 + 17 + 4285 + + + 20 + 214 + 428 + + - file + msg line 12 - + + + 1 + 2 + 42213 + + + 2 + 3 + 5999 + + + 3 + 5 + 4285 + + + 5 + 52 + 3214 + + - file + msg col 12 - + + + 1 + 2 + 51856 + + + 2 + 5 + 3857 + + - file + msg package 12 - + + + 1 + 2 + 49499 + + + 2 + 5 + 4714 + + + 5 + 10 + 1499 + + - file + msg idx 12 - - - - - - line - id - - - 12 - - - - - - line - kind - - - 12 - + + + 1 + 2 + 33213 + + + 2 + 3 + 7928 + + + 3 + 4 + 5999 + + + 4 + 8 + 4285 + + + 8 + 163 + 4285 + + - line - msg + rawpos + id 12 - + + + 1 + 2 + 146355 + + + 2 + 93 + 9642 + + - line - rawpos + rawpos + kind 12 - + + + 1 + 2 + 155997 + + - line - file + rawpos + msg 12 - + + + 1 + 2 + 155354 + + + 3 + 8 + 642 + + - line - col + rawpos + file 12 - + + + 1 + 2 + 155997 + + - line - package + rawpos + line 12 - + + + 1 + 2 + 155997 + + - line - idx + rawpos + col 12 - + + + 1 + 2 + 155997 + + - col - id + rawpos + package 12 - + + + 1 + 2 + 155783 + + + 7 + 8 + 214 + + - col - kind + rawpos + idx 12 - + + + 1 + 2 + 146569 + + + 2 + 93 + 9428 + + - col - msg + file + id 12 - + + + 1 + 2 + 26999 + + + 2 + 3 + 8142 + + + 3 + 4 + 5785 + + + 4 + 6 + 4928 + + + 6 + 11 + 4928 + + + 11 + 19 + 4285 + + + 19 + 93 + 1285 + + - col - rawpos + file + kind 12 - + + + 1 + 2 + 50570 + + + 2 + 3 + 5357 + + + 3 + 4 + 428 + + - col - file + file + msg 12 - + + + 1 + 2 + 28071 + + + 2 + 3 + 9856 + + + 3 + 4 + 7071 + + + 4 + 6 + 4499 + + + 6 + 11 + 5142 + + + 11 + 17 + 1714 + + - col - line + file + rawpos 12 - + + + 1 + 2 + 28071 + + + 2 + 3 + 10071 + + + 3 + 4 + 6642 + + + 4 + 6 + 4071 + + + 6 + 11 + 4928 + + + 11 + 18 + 2571 + + - col - package + file + line 12 - - - - - - col - idx - + + + 1 + 2 + 29999 + + + 2 + 3 + 9214 + + + 3 + 4 + 5999 + + + 4 + 6 + 5142 + + + 6 + 12 + 5142 + + + 12 + 16 + 857 + + + + + + + file + col + 12 - + + + 1 + 2 + 43499 + + + 2 + 3 + 5785 + + + 3 + 5 + 5142 + + + 5 + 9 + 1928 + + - package + file + package + + + 12 + + + 1 + 2 + 50999 + + + 2 + 4 + 4285 + + + 4 + 9 + 1071 + + + + + + + file + idx + + + 12 + + + 1 + 2 + 28285 + + + 2 + 3 + 7499 + + + 3 + 4 + 5785 + + + 4 + 5 + 2571 + + + 5 + 8 + 4499 + + + 8 + 13 + 4499 + + + 13 + 93 + 3214 + + + + + + + line id 12 - + + + 1 + 2 + 6642 + + + 2 + 3 + 3642 + + + 3 + 4 + 1499 + + + 4 + 5 + 1071 + + + 5 + 6 + 1071 + + + 6 + 7 + 2142 + + + 7 + 13 + 1714 + + + 14 + 31 + 1714 + + + 31 + 50 + 1714 + + + 53 + 208 + 642 + + - package + line kind 12 - + + + 1 + 2 + 17999 + + + 2 + 3 + 2999 + + + 3 + 4 + 857 + + - package + line msg 12 - + + + 1 + 2 + 7714 + + + 2 + 3 + 3214 + + + 3 + 4 + 2571 + + + 4 + 5 + 1928 + + + 5 + 6 + 1499 + + + 6 + 10 + 1714 + + + 10 + 16 + 1714 + + + 16 + 23 + 1499 + + - package + line rawpos 12 - + + + 1 + 2 + 6857 + + + 2 + 3 + 3642 + + + 3 + 4 + 2142 + + + 4 + 5 + 1285 + + + 5 + 6 + 1499 + + + 6 + 7 + 1714 + + + 7 + 19 + 1928 + + + 20 + 32 + 1714 + + + 32 + 87 + 1071 + + - package + line file 12 - + + + 1 + 2 + 7071 + + + 2 + 3 + 4071 + + + 3 + 4 + 1928 + + + 4 + 5 + 1714 + + + 5 + 6 + 857 + + + 6 + 7 + 1928 + + + 7 + 18 + 1499 + + + 18 + 27 + 1714 + + + 29 + 86 + 1071 + + + + + + + line + col + + + 12 + + + 1 + 2 + 10499 + + + 2 + 3 + 3857 + + + 3 + 4 + 2571 + + + 4 + 5 + 2785 + + + 5 + 9 + 1928 + + + 10 + 11 + 214 + + + + + + + line + package + + + 12 + + + 1 + 2 + 8142 + + + 2 + 3 + 5571 + + + 3 + 4 + 2571 + + + 4 + 6 + 1714 + + + 7 + 10 + 1928 + + + 10 + 19 + 1714 + + + 21 + 22 + 214 + + + + + + + line + idx + + + 12 + + + 1 + 2 + 7071 + + + 2 + 3 + 3642 + + + 3 + 4 + 1714 + + + 4 + 6 + 1928 + + + 6 + 7 + 2142 + + + 7 + 14 + 1714 + + + 15 + 30 + 1714 + + + 30 + 77 + 1714 + + + 187 + 188 + 214 + + + + + + + col + id + + + 12 + + + 1 + 2 + 3428 + + + 2 + 3 + 2142 + + + 3 + 4 + 1071 + + + 4 + 7 + 642 + + + 7 + 10 + 857 + + + 10 + 14 + 642 + + + 17 + 24 + 857 + + + 107 + 768 + 428 + + + + + + + col + kind + + + 12 + + + 1 + 2 + 8142 + + + 2 + 3 + 1928 + + + + + + + col + msg + + + 12 + + + 1 + 2 + 4499 + + + 2 + 3 + 2357 + + + 3 + 6 + 857 + + + 6 + 9 + 857 + + + 9 + 12 + 642 + + + 13 + 84 + 857 + + + + + + + col + rawpos + + + 12 + + + 1 + 2 + 3428 + + + 2 + 3 + 2571 + + + 3 + 4 + 1071 + + + 4 + 8 + 857 + + + 8 + 14 + 857 + + + 17 + 22 + 857 + + + 100 + 436 + 428 + + + + + + + col + file + + + 12 + + + 1 + 2 + 4714 + + + 2 + 3 + 2357 + + + 3 + 7 + 857 + + + 7 + 8 + 428 + + + 9 + 11 + 857 + + + 15 + 223 + 857 + + + + + + + col + line + + + 12 + + + 1 + 2 + 4285 + + + 2 + 3 + 2357 + + + 3 + 4 + 857 + + + 4 + 7 + 857 + + + 7 + 12 + 642 + + + 13 + 19 + 857 + + + 80 + 81 + 214 + + + + + + + col + package + + + 12 + + + 1 + 2 + 5785 + + + 2 + 3 + 2142 + + + 3 + 5 + 857 + + + 8 + 13 + 857 + + + 14 + 45 + 428 + + + + + + + col + idx + + + 12 + + + 1 + 2 + 3642 + + + 2 + 3 + 2142 + + + 3 + 4 + 1071 + + + 4 + 7 + 642 + + + 7 + 9 + 857 + + + 9 + 14 + 857 + + + 17 + 358 + 857 + + + + + + + package + id + + + 12 + + + 1 + 2 + 11571 + + + 2 + 3 + 1285 + + + 3 + 5 + 1285 + + + 5 + 10 + 1285 + + + 15 + 204 + 1285 + + + 417 + 418 + 214 + + + + + + + package + kind + + + 12 + + + 1 + 2 + 16285 + + + 2 + 4 + 642 + + + + + + + package + msg + + + 12 + + + 1 + 2 + 11571 + + + 2 + 3 + 1714 + + + 3 + 4 + 1285 + + + 4 + 15 + 1499 + + + 25 + 71 + 857 + + + + + + + package + rawpos + + + 12 + + + 1 + 2 + 11571 + + + 2 + 3 + 1285 + + + 3 + 4 + 1285 + + + 5 + 10 + 1285 + + + 15 + 128 + 1285 + + + 258 + 259 + 214 + + + + + + + package + file + + + 12 + + + 1 + 2 + 14356 + + + 2 + 4 + 1285 + + + 4 + 95 + 1285 + + + + + + + package + line + + + 12 + + + 1 + 2 + 11785 + + + 2 + 3 + 1285 + + + 3 + 5 + 1285 + + + 5 + 15 + 1285 + + + 15 + 68 + 1285 + + + + + + + package + col + + + 12 + + + 1 + 2 + 14142 + + + 2 + 5 + 1285 + + + 5 + 23 + 1285 + + + 23 + 24 + 214 + + + + + + + package + idx + + + 12 + + + 1 + 2 + 11571 + + + 2 + 3 + 1285 + + + 3 + 5 + 1285 + + + 5 + 10 + 1285 + + + 15 + 204 + 1285 + + + 417 + 418 + 214 + + + + + + + idx + id + + + 12 + + + 1 + 2 + 45856 + + + 2 + 3 + 9642 + + + 3 + 4 + 8357 + + + 4 + 5 + 18428 + + + 5 + 26 + 6857 + + + 79 + 80 + 214 + + + + + + + idx + kind + + + 12 + + + 1 + 2 + 86570 + + + 2 + 4 + 2785 + + + + + + + idx + msg + + + 12 + + + 1 + 2 + 45856 + + + 2 + 3 + 11999 + + + 3 + 4 + 14356 + + + 4 + 5 + 14785 + + + 5 + 60 + 2357 + + + + + + + idx + rawpos + + + 12 + + + 1 + 2 + 45856 + + + 2 + 3 + 9642 + + + 3 + 4 + 8357 + + + 4 + 5 + 18428 + + + 5 + 26 + 6857 + + + 73 + 74 + 214 + + + + + + + idx + file + + + 12 + + + 1 + 2 + 45856 + + + 2 + 3 + 9642 + + + 3 + 4 + 8357 + + + 4 + 5 + 18428 + + + 5 + 26 + 6857 + + + 44 + 45 + 214 + + + + + + + idx + line + + + 12 + + + 1 + 2 + 45856 + + + 2 + 3 + 10285 + + + 3 + 4 + 10071 + + + 4 + 5 + 18214 + + + 5 + 19 + 4928 + + + + + + + idx + col + + + 12 + + + 1 + 2 + 66856 + + + 2 + 3 + 17999 + + + 3 + 9 + 4499 + + + + + + + idx + package + + + 12 + + + 1 + 2 + 45856 + + + 2 + 3 + 9642 + + + 3 + 4 + 8357 + + + 4 + 5 + 18428 + + + 5 + 26 + 6857 + + + 79 + 80 + 214 + + + + + + + + + has_ellipsis + 45900 + + + id + 45900 + + + + + + variadic + 2105580 + + + id + 2105580 + + + + + + typeparam + 331358 + + + tp + 331358 + + + name + 19381 + + + bound + 42513 + + + parent + 249456 + + + idx + 3126 + + + + + tp + name + + + 12 + + + 1 + 2 + 331358 + + + + + + + tp + bound + + + 12 + + + 1 + 2 + 331358 + + + + + + + tp + parent + + + 12 + + + 1 + 2 + 331358 + + + + + + + tp + idx + + + 12 + + + 1 + 2 + 331358 + + + + + + + name + tp + + + 12 + + + 1 + 2 + 6877 + + + 2 + 3 + 2500 + + + 3 + 4 + 2500 + + + 4 + 6 + 1250 + + + 6 + 9 + 1250 + + + 10 + 12 + 1250 + + + 27 + 34 + 1250 + + + 69 + 74 + 1250 + + + 109 + 145 + 1250 + + + + + + + name + bound + + + 12 + + + 1 + 2 + 12504 + + + 2 + 3 + 1875 + + + 3 + 4 + 2500 + + + 4 + 12 + 1250 + + + 12 + 32 + 1250 + + + + + + + name + parent + + + 12 + + + 1 + 2 + 6877 + + + 2 + 3 + 2500 + + + 3 + 4 + 2500 + + + 4 + 6 + 1250 + + + 6 + 9 + 1250 + + + 10 + 12 + 1250 + + + 27 + 34 + 1250 + + + 69 + 74 + 1250 + + + 109 + 145 + 1250 + + + + + + + name + idx + + + 12 + + + 1 + 2 + 14379 + + + 2 + 3 + 3126 + + + 3 + 4 + 1250 + + + 4 + 5 + 625 + + + + + + + bound + tp + + + 12 + + + 1 + 2 + 32510 + + + 2 + 4 + 3126 + + + 4 + 7 + 3751 + + + 15 + 271 + 3126 + + - package - line + bound + name 12 - + + + 1 + 2 + 36887 + + + 2 + 3 + 3751 + + + 4 + 18 + 1875 + + - package - col + bound + parent 12 - + + + 1 + 2 + 33761 + + + 2 + 4 + 1875 + + + 4 + 7 + 3751 + + + 15 + 260 + 3126 + + - package + bound idx 12 - + + + 1 + 2 + 38762 + + + 2 + 6 + 3751 + + - idx - id + parent + tp 12 - + + + 1 + 2 + 183185 + + + 2 + 3 + 55018 + + + 3 + 6 + 11253 + + - idx - kind + parent + name 12 - + + + 1 + 2 + 183185 + + + 2 + 3 + 55018 + + + 3 + 6 + 11253 + + - idx - msg + parent + bound 12 - + + + 1 + 2 + 187561 + + + 2 + 3 + 51892 + + + 3 + 5 + 10003 + + - idx - rawpos + parent + idx 12 - + + + 1 + 2 + 183185 + + + 2 + 3 + 55018 + + + 3 + 6 + 11253 + + idx - file + tp 12 - + + + 1 + 2 + 625 + + + 6 + 7 + 625 + + + 18 + 19 + 625 + + + 110 + 111 + 625 + + + 395 + 396 + 625 + + idx - line + name 12 - + + + 1 + 2 + 625 + + + 4 + 5 + 625 + + + 6 + 7 + 625 + + + 13 + 14 + 625 + + + 19 + 20 + 625 + + idx - col + bound 12 - + + + 1 + 2 + 625 + + + 3 + 4 + 625 + + + 9 + 10 + 625 + + + 11 + 12 + 625 + + + 57 + 58 + 625 + + idx - package + parent 12 - + + + 1 + 2 + 625 + + + 6 + 7 + 625 + + + 18 + 19 + 625 + + + 110 + 111 + 625 + + + 395 + 396 + 625 + + - - has_ellipsis - 268 - - - id - 268 - - - -