Skip to content

Commit 6e1c7f1

Browse files
committed
Refactor elementAppliesToQualifier
This is needed for performance when there are lots of embeddings.
1 parent f94edc0 commit 6e1c7f1

File tree

2 files changed

+38
-35
lines changed

2 files changed

+38
-35
lines changed

go/ql/lib/semmle/go/dataflow/ExternalFlow.qll

+4-6
Original file line numberDiff line numberDiff line change
@@ -475,10 +475,9 @@ SourceSinkInterpretationInput::SourceOrSinkElement interpretElement(
475475
// Go does not need to distinguish functions with signature
476476
signature = "" and
477477
exists(string p | p = interpretPackage(pkg) |
478-
result.hasTypeInfo(p, type, subtypes) and
479-
(
480-
result.asFieldEntity().hasQualifiedName(p, type, name) or
481-
result.asMethodEntity().hasQualifiedName(p, type, name)
478+
exists(Entity e | result.hasFullInfo(e, p, type, subtypes) |
479+
e.(Field).hasQualifiedName(p, type, name) or
480+
e.(Method).hasQualifiedName(p, type, name)
482481
)
483482
or
484483
subtypes = true and
@@ -488,8 +487,7 @@ SourceSinkInterpretationInput::SourceOrSinkElement interpretElement(
488487
m2.getName() = name and
489488
m2.getReceiverBaseType().hasQualifiedName(pkg2, type2)
490489
|
491-
result.asMethodEntity() = m2 and
492-
result.hasTypeInfo(pkg2, type2, subtypes)
490+
result.hasFullInfo(m2, pkg2, type2, subtypes)
493491
)
494492
or
495493
type = "" and

go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll

+34-29
Original file line numberDiff line numberDiff line change
@@ -185,23 +185,23 @@ module SourceSinkInterpretationInput implements
185185

186186
/**
187187
* Holds if this source or sink element is a method or field that was specified
188-
* with the given values for `pkg`, `type` and `subtypes`.
188+
* with the given values for `e`, `pkg`, `type` and `subtypes`.
189189
*/
190-
predicate hasTypeInfo(string pkg, string type, boolean subtypes) {
191-
this = TMethodEntityElement(_, pkg, type, subtypes) or
192-
this = TFieldEntityElement(_, pkg, type, subtypes)
190+
predicate hasFullInfo(Entity e, string pkg, string type, boolean subtypes) {
191+
this = TMethodEntityElement(e, pkg, type, subtypes) or
192+
this = TFieldEntityElement(e, pkg, type, subtypes)
193193
}
194194

195195
/** Gets a textual representation of this source or sink element. */
196196
string toString() {
197-
not this.hasTypeInfo(_, _, _) and
197+
(this instanceof TOtherEntityElement or this instanceof TAstElement) and
198198
result = "element representing " + [this.asEntity().toString(), this.asAstNode().toString()]
199199
or
200-
exists(string pkg, string name, boolean subtypes |
201-
this.hasTypeInfo(pkg, name, subtypes) and
200+
exists(Entity e, string pkg, string name, boolean subtypes |
201+
this.hasFullInfo(e, pkg, name, subtypes) and
202202
result =
203-
"element representing " + this.asEntity().toString() + " with receiver type " + pkg + "." +
204-
name + " and subtypes=" + subtypes
203+
"element representing " + e.toString() + " with receiver type " + pkg + "." + name +
204+
" and subtypes=" + subtypes
205205
)
206206
}
207207

@@ -249,8 +249,8 @@ module SourceSinkInterpretationInput implements
249249
(
250250
result.asOtherEntity() = callTarget
251251
or
252-
result.asMethodEntity() = callTarget and
253-
elementAppliesToQualifier(result, cn.getReceiver())
252+
callTarget instanceof Method and
253+
result = getElementWithQualifier(callTarget, cn.getReceiver())
254254
)
255255
)
256256
}
@@ -278,22 +278,20 @@ module SourceSinkInterpretationInput implements
278278
}
279279

280280
/**
281-
* Holds if method or field spec `sse` applies in the context of qualifier `qual`.
281+
* Gets a method or field spec for `e` which applies in the context of
282+
* qualifier `qual`.
282283
*
283-
* Note that naively checking `sse.asEntity()`'s qualified name is not correct, because
284-
* `Method`s and `Field`s may have multiple qualified names due to embedding. We must instead
285-
* check that the specific name given by `sse.hasTypeInfo` refers to either `qual`'s type
286-
* or to a type it embeds.
284+
* Note that naively checking `e`'s qualified name is not correct, because
285+
* `Method`s and `Field`s may have multiple qualified names due to embedding.
286+
* We must instead check that the package and type name given by
287+
* `result.hasFullInfo` refer to either `qual`'s type or to a type it embeds.
287288
*/
288-
bindingset[sse, qual]
289+
bindingset[e, qual]
289290
pragma[inline_late]
290-
private predicate elementAppliesToQualifier(SourceOrSinkElement sse, DataFlow::Node qual) {
291-
exists(
292-
string pkg, string typename, boolean subtypes, Type syntacticQualBaseType, Type targetType
293-
|
294-
sse.hasTypeInfo(pkg, typename, subtypes) and
295-
targetType.hasQualifiedName(pkg, typename) and
296-
syntacticQualBaseType = getSyntacticQualifierBaseType(qual)
291+
private SourceOrSinkElement getElementWithQualifier(Entity e, DataFlow::Node qual) {
292+
exists(boolean subtypes, Type syntacticQualBaseType, Type targetType |
293+
syntacticQualBaseType = getSyntacticQualifierBaseType(qual) and
294+
result = constructElement(e, targetType, subtypes)
297295
|
298296
subtypes = [true, false] and
299297
syntacticQualBaseType = targetType
@@ -307,12 +305,20 @@ module SourceSinkInterpretationInput implements
307305
or
308306
// `syntacticQualBaseType`'s underlying type might be a struct type and `sse`
309307
// might be a promoted method or field in it.
310-
targetType =
311-
getIntermediateEmbeddedType(sse.asMethodEntity(), syntacticQualBaseType.getUnderlyingType())
308+
targetType = getIntermediateEmbeddedType(e, syntacticQualBaseType.getUnderlyingType())
312309
)
313310
)
314311
}
315312

313+
bindingset[e, targetType, subtypes]
314+
pragma[inline_late]
315+
private SourceOrSinkElement constructElement(Entity e, Type targetType, boolean subtypes) {
316+
exists(string pkg, string typename |
317+
targetType.hasQualifiedName(pkg, typename) and
318+
result.hasFullInfo(e, pkg, typename, subtypes)
319+
)
320+
}
321+
316322
/**
317323
* Gets the type of an embedded field of `st` which is on the path to `e`,
318324
* which is a promoted method or field of `st`, or its base type if it's a
@@ -388,8 +394,7 @@ module SourceSinkInterpretationInput implements
388394
or
389395
exists(DataFlow::FieldReadNode frn | frn = n |
390396
c = "" and
391-
frn.getField() = pragma[only_bind_into](e).asFieldEntity() and
392-
elementAppliesToQualifier(pragma[only_bind_into](e), frn.getBase())
397+
pragma[only_bind_into](e) = getElementWithQualifier(frn.getField(), frn.getBase())
393398
)
394399
)
395400
}
@@ -410,7 +415,7 @@ module SourceSinkInterpretationInput implements
410415
|
411416
c = "" and
412417
fw.writesField(base, f, node.asNode()) and
413-
elementAppliesToQualifier(pragma[only_bind_into](e), base)
418+
pragma[only_bind_into](e) = getElementWithQualifier(f, base)
414419
)
415420
}
416421
}

0 commit comments

Comments
 (0)