Skip to content

Commit 94adcc9

Browse files
committed
C#: Improve performance and correctness of IndexerProperty::getAnIndexerCall()
Performance has been improved via suitable predicate folding, and correctness has been improved as the line ``` result = getType().(RefType).getAnIndexer().getAnAccessor().getACall() ``` was missing a `getABaseType*()` (now using the simpler `hasMember()` predicate instead).
1 parent 94e4bd8 commit 94adcc9

File tree

1 file changed

+32
-6
lines changed

1 file changed

+32
-6
lines changed

csharp/ql/src/semmle/code/csharp/Property.qll

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,16 @@ class TrivialProperty extends Property {
505505
* A `Property` which holds a type with an indexer.
506506
*/
507507
class IndexerProperty extends Property {
508-
IndexerProperty() { exists(getType().(RefType).getABaseType*().getAnIndexer()) }
508+
Indexer i;
509+
510+
IndexerProperty() { this.getType().(RefType).hasMember(i) }
511+
512+
pragma[nomagic]
513+
private IndexerCall getAnIndexerCall0() {
514+
exists(Expr qualifier | qualifier = result.getQualifier() |
515+
DataFlow::localFlow(DataFlow::exprNode(this.getAnAccess()), DataFlow::exprNode(qualifier))
516+
)
517+
}
509518

510519
/**
511520
* Gets a call to the indexer of the type returned by this property, for a value returned by this
@@ -514,10 +523,27 @@ class IndexerProperty extends Property {
514523
* This tracks instances returned by the property using local data flow.
515524
*/
516525
IndexerCall getAnIndexerCall() {
517-
result = getType().(RefType).getAnIndexer().getAnAccessor().getACall() and
518-
// The qualifier of this indexer call should be a value returned from an access of this property
519-
exists(Expr qualifier | qualifier = result.(IndexerAccess).getQualifier() |
520-
DataFlow::localFlow(DataFlow::exprNode(this.getAnAccess()), DataFlow::exprNode(qualifier))
521-
)
526+
result = this.getAnIndexerCall0() and
527+
// Omitting the constraint below would potentially include
528+
// too many indexer calls, for example the call to the indexer
529+
// setter at `dict[0]` in
530+
//
531+
// ```
532+
// class A
533+
// {
534+
// Dictionary<int, string> dict;
535+
// public IReadonlyDictionary<int, string> Dict { get => dict; }
536+
// }
537+
//
538+
// class B
539+
// {
540+
// void M(A a)
541+
// {
542+
// var dict = (Dictionary<int, string>) a.Dict;
543+
// dict[0] = "";
544+
// }
545+
// }
546+
// ```
547+
result.getIndexer() = i
522548
}
523549
}

0 commit comments

Comments
 (0)