@@ -58,16 +58,28 @@ predicate imported_module_used_in_doctest(Import imp) {
5858}
5959
6060predicate imported_module_used_in_typehint ( Import imp ) {
61- exists ( string modname |
62- imp .getAName ( ) .getAsname ( ) .( Name ) .getId ( ) = modname
63- and
61+ exists ( string modname , Location loc |
62+ imp .getAName ( ) .getAsname ( ) .( Name ) .getId ( ) = modname and
63+ loc .getFile ( ) = imp .getScope ( ) .( Module ) .getFile ( )
64+ |
6465 /* Look for typehints containing the patterns:
6566 * # type: …name…
6667 */
6768 exists ( Comment typehint |
68- typehint . getLocation ( ) . getFile ( ) = imp . getScope ( ) . ( Module ) . getFile ( ) and
69+ loc = typehint . getLocation ( ) and
6970 typehint .getText ( ) .regexpMatch ( "# type:.*" + modname + ".*" )
7071 )
72+ or
73+ // Type hint is inside a string annotation, as needed for forward references
74+ exists ( string typehint , Expr annotation |
75+ annotation = any ( Arguments a ) .getAnAnnotation ( )
76+ or
77+ annotation = any ( AnnAssign a ) .getAnnotation ( )
78+ |
79+ annotation .pointsTo ( Value:: forString ( typehint ) ) and
80+ loc = annotation .getLocation ( ) and
81+ typehint .regexpMatch ( ".*\\b" + modname + "\\b.*" )
82+ )
7183 )
7284}
7385
@@ -100,6 +112,11 @@ predicate unused_import(Import imp, Variable name) {
100112 not imported_module_used_in_doctest ( imp )
101113 and
102114 not imported_module_used_in_typehint ( imp )
115+ and
116+ /* Only consider import statements that actually point-to something (possibly an unknown module).
117+ * If this is not the case, it's likely that the import statement never gets executed.
118+ */
119+ imp .getAName ( ) .getValue ( ) .pointsTo ( _)
103120}
104121
105122
0 commit comments