@@ -428,25 +428,25 @@ class DereferenceableExpr extends Expr {
428428
429429/**
430430 * An expression that evaluates to a collection. That is, an expression whose
431- * (transitive, reflexive) base type is `IEnumerable`(`<T>`) .
431+ * (transitive, reflexive) base type is `IEnumerable`.
432432 */
433433class CollectionExpr extends Expr {
434434 CollectionExpr ( ) {
435- exists ( Interface i |
436- i = this .getType ( ) .( ValueOrRefType ) .getABaseType * ( ) .getSourceDeclaration ( )
437- |
438- i instanceof SystemCollectionsIEnumerableInterface or
439- i instanceof SystemCollectionsGenericIEnumerableTInterface
440- )
435+ this .getType ( ) .( ValueOrRefType ) .getABaseType * ( ) instanceof SystemCollectionsIEnumerableInterface
441436 }
442437
443- /** Gets an expression that computes the size of this collection. */
444- private Expr getASizeExpr ( ) {
438+ /**
439+ * Gets an expression that computes the size of this collection. `lowerBound`
440+ * indicates whether the expression only computes a lower bound.
441+ */
442+ private Expr getASizeExpr ( boolean lowerBound ) {
443+ lowerBound = false and
445444 result = any ( PropertyRead pr |
446445 this = pr .getQualifier ( ) and
447446 pr .getTarget ( ) = any ( SystemArrayClass x ) .getLengthProperty ( )
448447 )
449448 or
449+ lowerBound = false and
450450 result = any ( PropertyRead pr |
451451 this = pr .getQualifier ( ) and
452452 pr
@@ -459,59 +459,61 @@ class CollectionExpr extends Expr {
459459 or
460460 result = any ( MethodCall mc |
461461 mc .getTarget ( ) .getSourceDeclaration ( ) = any ( SystemLinq:: SystemLinqEnumerableClass x )
462- .getCountMethod ( ) and
463- this = mc .getArgument ( 0 )
462+ .getACountMethod ( ) and
463+ this = mc .getArgument ( 0 ) and
464+ if mc .getNumberOfArguments ( ) = 1 then lowerBound = false else lowerBound = true
464465 )
465466 }
466467
467468 private Expr getABooleanEmptinessCheck ( BooleanValue v , boolean isEmpty ) {
468469 exists ( boolean branch | branch = v .getValue ( ) |
469- exists ( Expr sizeOf | sizeOf = this . getASizeExpr ( ) |
470- result = any ( ComparisonTest ct |
471- ct .getAnArgument ( ) = sizeOf and
472- (
473- // x.Length == 0
474- ct . getComparisonKind ( ) . isEquality ( ) and
475- ct .getAnArgument ( ) .getValue ( ) . toInt ( ) = 0 and
476- branch = isEmpty
477- or
478- // x.Length == k, k > 0
479- ct . getComparisonKind ( ) . isEquality ( ) and
480- ct .getAnArgument ( ) .getValue ( ) . toInt ( ) > 0 and
481- branch = true and
482- isEmpty = false
483- or
484- // x.Length != 0
485- ct . getComparisonKind ( ) . isInequality ( ) and
486- ct .getAnArgument ( ) .getValue ( ) . toInt ( ) = 0 and
487- branch = isEmpty . booleanNot ( )
488- or
489- // x.Length != k, k != 0
490- ct . getComparisonKind ( ) . isInequality ( ) and
491- ct .getAnArgument ( ) .getValue ( ) . toInt ( ) != 0 and
492- branch = false and
493- isEmpty = false
494- or
495- // x.Length > k, k >= 0
496- ct . getComparisonKind ( ) . isLessThan ( ) and
497- ct .getFirstArgument ( ) .getValue ( ) . toInt ( ) >= 0 and
498- branch = true and
499- isEmpty = false
500- or
501- // x.Length >= k, k > 0
502- ct . getComparisonKind ( ) . isLessThanEquals ( ) and
503- ct .getFirstArgument ( ) .getValue ( ) . toInt ( ) > 0 and
504- branch = true and
505- isEmpty = false
506- )
507- ) . getExpr ( )
508- )
470+ result = any ( ComparisonTest ct |
471+ exists ( boolean lowerBound |
472+ ct .getAnArgument ( ) = this . getASizeExpr ( lowerBound ) and
473+ if isEmpty = true then lowerBound = false else any ( )
474+ |
475+ // x.Length == 0
476+ ct .getComparisonKind ( ) .isEquality ( ) and
477+ ct . getAnArgument ( ) . getValue ( ) . toInt ( ) = 0 and
478+ branch = isEmpty
479+ or
480+ // x.Length == k, k > 0
481+ ct .getComparisonKind ( ) .isEquality ( ) and
482+ ct . getAnArgument ( ) . getValue ( ) . toInt ( ) > 0 and
483+ branch = true and
484+ isEmpty = false
485+ or
486+ // x.Length != 0
487+ ct .getComparisonKind ( ) .isInequality ( ) and
488+ ct . getAnArgument ( ) . getValue ( ) . toInt ( ) = 0 and
489+ branch = isEmpty . booleanNot ( )
490+ or
491+ // x.Length != k, k != 0
492+ ct .getComparisonKind ( ) .isInequality ( ) and
493+ ct . getAnArgument ( ) . getValue ( ) . toInt ( ) != 0 and
494+ branch = false and
495+ isEmpty = false
496+ or
497+ // x.Length > k, k >= 0
498+ ct .getComparisonKind ( ) .isLessThan ( ) and
499+ ct . getFirstArgument ( ) . getValue ( ) . toInt ( ) >= 0 and
500+ branch = true and
501+ isEmpty = false
502+ or
503+ // x.Length >= k, k > 0
504+ ct .getComparisonKind ( ) .isLessThanEquals ( ) and
505+ ct . getFirstArgument ( ) . getValue ( ) . toInt ( ) > 0 and
506+ branch = true and
507+ isEmpty = false
508+ )
509+ ) . getExpr ( )
509510 or
510511 result = any ( MethodCall mc |
511512 mc .getTarget ( ) .getSourceDeclaration ( ) = any ( SystemLinq:: SystemLinqEnumerableClass x )
512- .getAnyMethod ( ) and
513+ .getAnAnyMethod ( ) and
513514 this = mc .getArgument ( 0 ) and
514- branch = isEmpty .booleanNot ( )
515+ branch = isEmpty .booleanNot ( ) and
516+ if branch = false then mc .getNumberOfArguments ( ) = 1 else any ( )
515517 )
516518 )
517519 }
@@ -526,8 +528,8 @@ class CollectionExpr extends Expr {
526528 * For example, if the expression `x.Length != 0` evaluates to `true` then the
527529 * expression `x` is guaranteed to be non-empty.
528530 */
529- Expr getAnEmptinessCheck ( AbstractValue v , boolean isNull ) {
530- result = this .getABooleanEmptinessCheck ( v , isNull )
531+ Expr getAnEmptinessCheck ( AbstractValue v , boolean isEmpty ) {
532+ result = this .getABooleanEmptinessCheck ( v , isEmpty )
531533 }
532534}
533535
@@ -1646,6 +1648,8 @@ module Internal {
16461648 predicate emptyValue ( Expr e ) {
16471649 e .( ArrayCreation ) .getALengthArgument ( ) .getValue ( ) .toInt ( ) = 0
16481650 or
1651+ e .( ArrayInitializer ) .hasNoElements ( )
1652+ or
16491653 exists ( Expr mid | emptyValue ( mid ) |
16501654 mid = e .( AssignExpr ) .getRValue ( )
16511655 or
@@ -1655,8 +1659,8 @@ module Internal {
16551659 exists ( PreSsa:: Definition def | emptyDef ( def ) | firstReadSameVarUniquePredecesssor ( def , e ) )
16561660 or
16571661 exists ( MethodCall mc |
1658- mc .getTarget ( ) .getSourceDeclaration ( ) = any ( SystemCollectionsGenericListClass c )
1659- .getClearMethod ( ) and
1662+ mc .getTarget ( ) .getAnUltimateImplementee ( ) . getSourceDeclaration ( ) = any ( SystemCollectionsGenericICollectionInterface c
1663+ ) .getClearMethod ( ) and
16601664 adjacentReadPairSameVarUniquePredecessor ( mc .getQualifier ( ) , e )
16611665 )
16621666 }
@@ -1667,6 +1671,8 @@ module Internal {
16671671 length .getValue ( ) .toInt ( ) != 0
16681672 )
16691673 or
1674+ e .( ArrayInitializer ) .getNumberOfElements ( ) > 0
1675+ or
16701676 exists ( Expr mid | nonEmptyValue ( mid ) |
16711677 mid = e .( AssignExpr ) .getRValue ( )
16721678 or
@@ -1678,8 +1684,8 @@ module Internal {
16781684 )
16791685 or
16801686 exists ( MethodCall mc |
1681- mc .getTarget ( ) .getSourceDeclaration ( ) = any ( SystemCollectionsGenericListClass c )
1682- .getAddMethod ( ) and
1687+ mc .getTarget ( ) .getAnUltimateImplementee ( ) . getSourceDeclaration ( ) = any ( SystemCollectionsGenericICollectionInterface c
1688+ ) .getAddMethod ( ) and
16831689 adjacentReadPairSameVarUniquePredecessor ( mc .getQualifier ( ) , e )
16841690 )
16851691 }
0 commit comments