Skip to content

Commit c9c4c06

Browse files
authored
Merge pull request github#5633 from hvitved/csharp/get-a-source-type-perf
C#: Improve performance of `Dispatch::SimpleTypeDataFlow::getASourceType()`
2 parents a335bb0 + 036e181 commit c9c4c06

File tree

1 file changed

+55
-31
lines changed

1 file changed

+55
-31
lines changed

csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -636,31 +636,41 @@ private module Internal {
636636
)
637637
}
638638

639-
private predicate stepExpr0(Expr succ, Expr pred) {
640-
Steps::stepOpen(pred, succ)
641-
or
642-
exists(Assignable a |
643-
a instanceof Field or
644-
a instanceof Property
645-
|
646-
succ.(AssignableRead) = a.getAnAccess() and
647-
pred = a.getAnAssignedValue() and
648-
a = any(Modifiable m | not m.isEffectivelyPublic())
649-
)
650-
}
651-
652-
private predicate stepExpr(Expr succ, Expr pred) {
653-
stepExpr0(succ, pred) and
639+
private predicate stepExpr(Expr pred, Expr succ) {
640+
Steps::stepOpen(pred, succ) and
654641
// Do not step through down casts
655642
not downCast(succ) and
656643
// Only step when we may learn more about the actual type
657644
typeMayBeImprecise(succ.getType())
658645
}
659646

660-
private predicate stepTC(Expr succ, Expr pred) = fastTC(stepExpr/2)(succ, pred)
647+
private class AnalyzableFieldOrProperty extends Assignable, Modifiable {
648+
AnalyzableFieldOrProperty() {
649+
(
650+
this instanceof Field or
651+
this instanceof Property
652+
) and
653+
not this.isEffectivelyPublic() and
654+
exists(this.getAnAssignedValue())
655+
}
656+
657+
AssignableRead getARead() { result = this.getAnAccess() }
658+
}
661659

662660
private class Source extends Expr {
663-
Source() { not stepExpr(this, _) }
661+
Source() {
662+
not stepExpr(_, this) and
663+
not this = any(AnalyzableFieldOrProperty a).getARead()
664+
}
665+
666+
Type getType(boolean isExact) {
667+
result = this.getType() and
668+
if
669+
this instanceof ObjectCreation or
670+
this instanceof BaseAccess
671+
then isExact = true
672+
else isExact = false
673+
}
664674
}
665675

666676
private class Sink extends Expr {
@@ -680,24 +690,38 @@ private module Internal {
680690
this = any(DispatchCallImpl c).getArgument(_)
681691
}
682692

683-
Source getASource() { stepTC(this, result) }
693+
pragma[nomagic]
694+
Expr getAPred() { stepExpr*(result, this) }
695+
696+
pragma[nomagic]
697+
AnalyzableFieldOrProperty getAPredRead() { this.getAPred() = result.getARead() }
684698
}
685699

686-
/** Holds if the expression `e` has an exact type. */
687-
private predicate hasExactType(Expr e) {
688-
e instanceof ObjectCreation or
689-
e instanceof BaseAccess
700+
/** Gets a source type for sink expression `e`, using simple data flow. */
701+
Type getASourceType(Sink sink, boolean isExact) {
702+
result = sink.getAPred().(Source).getType(isExact)
703+
or
704+
result = sink.getAPredRead().(RelevantFieldOrProperty).getASourceType(isExact)
690705
}
691706

692-
/** Gets a source type for expression `e`, using simple data flow. */
693-
Type getASourceType(Sink e, boolean isExact) {
694-
exists(Source s |
695-
s = e.getASource() or
696-
s = e
697-
|
698-
result = s.getType() and
699-
if hasExactType(s) then isExact = true else isExact = false
700-
)
707+
private class RelevantFieldOrProperty extends AnalyzableFieldOrProperty {
708+
RelevantFieldOrProperty() {
709+
this = any(Sink s).getAPredRead()
710+
or
711+
this = any(RelevantFieldOrProperty a).getAPredRead()
712+
}
713+
714+
pragma[nomagic]
715+
Expr getAPred() { stepExpr*(result, this.getAnAssignedValue()) }
716+
717+
pragma[nomagic]
718+
AnalyzableFieldOrProperty getAPredRead() { this.getAPred() = result.getARead() }
719+
720+
Type getASourceType(boolean isExact) {
721+
result = this.getAPred().(Source).getType(isExact)
722+
or
723+
result = this.getAPredRead().(RelevantFieldOrProperty).getASourceType(isExact)
724+
}
701725
}
702726
}
703727

0 commit comments

Comments
 (0)