@@ -430,6 +430,29 @@ class ClassValue extends Value {
430430 this .hasAttribute ( "__getitem__" )
431431 }
432432
433+ /** Holds if this class is an iterator. */
434+ predicate isIterator ( ) {
435+ this .hasAttribute ( "__iter__" ) and
436+ (
437+ major_version ( ) = 3 and this .hasAttribute ( "__next__" )
438+ or
439+ /*
440+ * Because 'next' is a common method name we need to check that an __iter__
441+ * method actually returns this class. This is not needed for Py3 as the
442+ * '__next__' method exists to define a class as an iterator.
443+ */
444+
445+ major_version ( ) = 2 and
446+ this .hasAttribute ( "next" ) and
447+ exists ( ClassValue other , FunctionValue iter | other .declaredAttribute ( "__iter__" ) = iter |
448+ iter .getAnInferredReturnType ( ) = this
449+ )
450+ )
451+ or
452+ /* This will be redundant when we have C class information */
453+ this = ClassValue:: generator ( )
454+ }
455+
433456 /** Holds if this class is a container(). That is, does it have a __getitem__ method. */
434457 predicate isContainer ( ) { exists ( this .lookup ( "__getitem__" ) ) }
435458
@@ -583,11 +606,7 @@ abstract class FunctionValue extends CallableValue {
583606 }
584607
585608 /** Gets a class that this function may return */
586- ClassValue getAnInferredReturnType ( ) {
587- result = TBuiltinClassObject ( this .( BuiltinFunctionObjectInternal ) .getReturnType ( ) )
588- or
589- result = TBuiltinClassObject ( this .( BuiltinMethodObjectInternal ) .getReturnType ( ) )
590- }
609+ abstract ClassValue getAnInferredReturnType ( ) ;
591610}
592611
593612/** Class representing Python functions */
@@ -616,6 +635,13 @@ class PythonFunctionValue extends FunctionValue {
616635
617636 /** Gets a control flow node corresponding to a return statement in this function */
618637 ControlFlowNode getAReturnedNode ( ) { result = this .getScope ( ) .getAReturnValueFlowNode ( ) }
638+
639+ override ClassValue getAnInferredReturnType ( ) {
640+ /* We have to do a special version of this because builtin functions have no
641+ * explicit return nodes that we can query and get the class of.
642+ */
643+ result = this .getAReturnedNode ( ) .pointsTo ( ) .getClass ( )
644+ }
619645}
620646
621647/** Class representing builtin functions, such as `len` or `print` */
@@ -627,6 +653,13 @@ class BuiltinFunctionValue extends FunctionValue {
627653 override int minParameters ( ) { none ( ) }
628654
629655 override int maxParameters ( ) { none ( ) }
656+
657+ override ClassValue getAnInferredReturnType ( ) {
658+ /* We have to do a special version of this because builtin functions have no
659+ * explicit return nodes that we can query and get the class of.
660+ */
661+ result = TBuiltinClassObject ( this .( BuiltinFunctionObjectInternal ) .getReturnType ( ) )
662+ }
630663}
631664
632665/** Class representing builtin methods, such as `list.append` or `set.add` */
@@ -644,6 +677,10 @@ class BuiltinMethodValue extends FunctionValue {
644677 override int minParameters ( ) { none ( ) }
645678
646679 override int maxParameters ( ) { none ( ) }
680+
681+ override ClassValue getAnInferredReturnType ( ) {
682+ result = TBuiltinClassObject ( this .( BuiltinMethodObjectInternal ) .getReturnType ( ) )
683+ }
647684}
648685
649686/**
0 commit comments