Add implicit field reads for promoted method calls

This commit is contained in:
Owen Mansel-Chan
2021-03-24 09:50:41 +00:00
parent a89a42df6f
commit b507c0d584
2 changed files with 43 additions and 5 deletions

View File

@@ -401,6 +401,22 @@ class StructType extends @structtype, CompositeType {
)
}
/**
* Gets a method of `embeddedParent`, which is then embedded into this struct type.
*/
Method getMethodOfEmbedded(Field embeddedParent, string name, int depth) {
// embeddedParent is a field of 'this' at depth 'depth - 1'
this.hasFieldCand(_, embeddedParent, depth - 1, true) and
result.getName() = name and
(
result.getReceiverBaseType() = embeddedParent.getType()
or
result.getReceiverBaseType() = embeddedParent.getType().(PointerType).getBaseType()
or
methodhosts(result, embeddedParent.getType())
)
}
private predicate hasFieldCand(string name, Field f, int depth, boolean isEmbedded) {
f = this.getOwnField(name, isEmbedded) and depth = 0
or
@@ -450,6 +466,11 @@ class StructType extends @structtype, CompositeType {
strictcount(getFieldCand(name, depth, _)) = 1
}
Method getMethodAtDepth(string name, int depth) {
depth = min(int depthCand | hasMethodCand(name, _, depthCand)) and
result = unique(Method m | hasMethodCand(name, m, depth))
}
override predicate hasMethod(string name, SignatureType tp) {
exists(int mindepth |
mindepth = min(int depth | this.hasMethodCand(name, _, depth)) and

View File

@@ -55,17 +55,17 @@ private predicate isCond(Expr e) {
* field `B`, `B` contains an embedded field `C` and `C` contains the non-embedded field `x`.
* Then `a.x` implicitly reads `C` with index 1 and `B` with index 2.
*/
private predicate implicitFieldSelection(PromotedFieldSelector e, int index, Field implicitField) {
private predicate implicitFieldSelectionForField(PromotedSelector e, int index, Field implicitField) {
exists(StructType baseType, PromotedField child, int implicitFieldDepth |
baseType = e.getSelectedStructType() and
(
e.refersTo(child)
or
implicitFieldSelection(e, implicitFieldDepth + 1, child)
implicitFieldSelectionForField(e, implicitFieldDepth + 1, child)
)
|
child = baseType.getFieldOfEmbedded(implicitField, _, implicitFieldDepth + 1, _) and
exists(Field explicitField, int explicitFieldDepth |
exists(PromotedField explicitField, int explicitFieldDepth |
e.refersTo(explicitField) and baseType.getFieldAtDepth(_, explicitFieldDepth) = explicitField
|
index = explicitFieldDepth - implicitFieldDepth
@@ -73,6 +73,22 @@ private predicate implicitFieldSelection(PromotedFieldSelector e, int index, Fie
)
}
private predicate implicitFieldSelectionForMethod(PromotedSelector e, int index, Field implicitField) {
exists(StructType baseType, PromotedMethod method, int mDepth, int implicitFieldDepth |
baseType = e.getSelectedStructType() and
e.refersTo(method) and
baseType.getMethodAtDepth(_, mDepth) = method and
index = mDepth - implicitFieldDepth
|
method = baseType.getMethodOfEmbedded(implicitField, _, implicitFieldDepth + 1)
or
exists(PromotedField child |
child = baseType.getFieldOfEmbedded(implicitField, _, implicitFieldDepth + 1, _) and
implicitFieldSelectionForMethod(e, implicitFieldDepth + 1, child)
)
)
}
/**
* A node in the intra-procedural control-flow graph of a Go function or file.
*
@@ -333,8 +349,9 @@ newtype TControlFlowNode =
* If that field has a pointer type then this control-flow node also
* represents an implicit dereference of it.
*/
MkImplicitFieldSelection(PromotedFieldSelector e, int i, Field implicitField) {
implicitFieldSelection(e, i, implicitField)
MkImplicitFieldSelection(PromotedSelector e, int i, Field implicitField) {
implicitFieldSelectionForField(e, i, implicitField) or
implicitFieldSelectionForMethod(e, i, implicitField)
} or
/**
* A control-flow node that represents the start of the execution of a function or file.