@@ -402,7 +402,7 @@ class Expr extends StmtParent, @expr {
402402 */
403403 predicate hasImplicitConversion ( ) {
404404 exists ( Expr e |
405- exprconv ( underlyingElement ( this ) , unresolveElement ( e ) ) and e .( Cast ) .isImplicit ( )
405+ exprconv ( underlyingElement ( this ) , unresolveElement ( e ) ) and e .( Conversion ) .isImplicit ( )
406406 )
407407 }
408408
@@ -414,7 +414,7 @@ class Expr extends StmtParent, @expr {
414414 */
415415 predicate hasExplicitConversion ( ) {
416416 exists ( Expr e |
417- exprconv ( underlyingElement ( this ) , unresolveElement ( e ) ) and not e .( Cast ) .isImplicit ( )
417+ exprconv ( underlyingElement ( this ) , unresolveElement ( e ) ) and not e .( Conversion ) .isImplicit ( )
418418 )
419419 }
420420
@@ -453,12 +453,14 @@ class Expr extends StmtParent, @expr {
453453 * cast from B to C. Only (1) and (2) would be included.
454454 */
455455 Expr getExplicitlyConverted ( ) {
456- // result is this or one of its conversions
457- result = this .getConversion * ( ) and
458- // result is not an implicit conversion - it's either the expr or an explicit cast
459- ( result = this or not result .( Cast ) .isImplicit ( ) ) and
460- // there is no further explicit conversion after result
461- not exists ( Cast other | other = result .getConversion + ( ) and not other .isImplicit ( ) )
456+ // For performance, we avoid a full transitive closure over `getConversion`.
457+ // Since there can be several implicit conversions before and after an
458+ // explicit conversion, use `getImplicitlyConverted` to step over them
459+ // cheaply. Then, if there is an explicit conversion following the implict
460+ // conversion sequence, recurse to handle multiple explicit conversions.
461+ if this .getImplicitlyConverted ( ) .hasExplicitConversion ( )
462+ then result = this .getImplicitlyConverted ( ) .getConversion ( ) .getExplicitlyConverted ( )
463+ else result = this
462464 }
463465
464466 /**
0 commit comments