Skip to content

Commit

Permalink
Rework interface for querying private interface method ids
Browse files Browse the repository at this point in the history
  • Loading branch information
smowton committed Oct 8, 2024
1 parent 0f95a8d commit ab99509
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
category: minorAnalysis
---
* Added member predicates `StructTag.hasOwnFieldWithTag` and `Field.getTag`, which enable CodeQL queries to examine struct field tags.
* Added member predicate `InterfaceType.getMethodTypeByQualifiedName`, which enables CodeQL queries to distinguish interfaces with matching non-exported method names that are declared in different packages, and are therefore incompatible.
* Added member predicate `InterfaceType.hasPrivateMethodWithQualifiedName`, which enables CodeQL queries to distinguish interfaces with matching non-exported method names that are declared in different packages, and are therefore incompatible.
28 changes: 6 additions & 22 deletions go/ql/lib/semmle/go/Types.qll
Original file line number Diff line number Diff line change
Expand Up @@ -769,29 +769,13 @@ class InterfaceType extends @interfacetype, CompositeType {
}

/**
* Gets the type of method `qname` of this interface type.
*
* This differs from `getMethodType` in that if the method is not exported, the `qname`
* will be package-qualified. This means that the set of `qname`s` together with any
* embedded types fully distinguishes the interface from any other, whereas the set
* of names matched by `getMethodName` may be ambiguous between interfaces with matching
* exported methods and unexported methods that have matching names but belong to
* different packages.
*
* For example, `interface { Exported() int; notExported() int }` declared in two
* different packages defines two distinct types, but they appear identical according to
* `getMethodType`. If the packages were named `a` and `b`, `getMethodType` would yield
* `notExported -> int` for both, whereas this method would yield `a.notExported -> int`
* and `b.notExported -> int` respectively, while both yielding `Exported -> int`.
* Holds if this interface type has a private method `name`,
* with qualified name `qname` and type `type`.
*/
Type getMethodTypeByQualifiedName(string qname) {
exists(int i, string name | i >= 0 |
component_types(this, i, name, result) and
(
interface_private_method_ids(this, i, qname)
or
name = qname and not interface_private_method_ids(this, i, _)
)
predicate hasPrivateMethodWithQualifiedName(string name, string qname, Type type) {
exists(int i | i >= 0 |
component_types(this, i, name, type) and
interface_private_method_ids(this, i, qname)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ from NamedType nt, InterfaceType it, Type methodType, string id
where
nt.getName() = "MixedExportedAndNot" and
it = nt.getUnderlyingType() and
methodType = it.getMethodTypeByQualifiedName(id)
(
it.hasPrivateMethodWithQualifiedName(_, id, methodType)
or
it.hasMethod(id, methodType) and not it.hasPrivateMethodWithQualifiedName(id, _, _)
)
select it.pp(), methodType.pp(), id

0 comments on commit ab99509

Please sign in to comment.