Generate annotations from mypy AST and inferred types.
| 248 | |
| 249 | |
| 250 | class ASTAnnotateVisitor(TraverserVisitor): |
| 251 | """Generate annotations from mypy AST and inferred types.""" |
| 252 | |
| 253 | def __init__(self, type_map: dict[Expression, Type], mapper: Mapper) -> None: |
| 254 | self.anns: dict[int, list[Annotation]] = {} |
| 255 | self.ignored_lines: set[int] = set() |
| 256 | self.func_depth = 0 |
| 257 | self.type_map = type_map |
| 258 | self.mapper = mapper |
| 259 | |
| 260 | def visit_func_def(self, o: FuncDef, /) -> None: |
| 261 | if self.func_depth > 0: |
| 262 | self.annotate( |
| 263 | o, |
| 264 | "A nested function object is allocated each time statement is executed. " |
| 265 | + "A module-level function would be faster.", |
| 266 | ) |
| 267 | self.func_depth += 1 |
| 268 | super().visit_func_def(o) |
| 269 | self.func_depth -= 1 |
| 270 | |
| 271 | def visit_for_stmt(self, o: ForStmt, /) -> None: |
| 272 | self.check_iteration([o.expr], "For loop") |
| 273 | super().visit_for_stmt(o) |
| 274 | |
| 275 | def visit_dictionary_comprehension(self, o: DictionaryComprehension, /) -> None: |
| 276 | self.check_iteration(o.sequences, "Comprehension") |
| 277 | super().visit_dictionary_comprehension(o) |
| 278 | |
| 279 | def visit_generator_expr(self, o: GeneratorExpr, /) -> None: |
| 280 | self.check_iteration(o.sequences, "Comprehension or generator") |
| 281 | super().visit_generator_expr(o) |
| 282 | |
| 283 | def check_iteration(self, expressions: list[Expression], kind: str) -> None: |
| 284 | for expr in expressions: |
| 285 | typ = self.get_type(expr) |
| 286 | if isinstance(typ, AnyType): |
| 287 | self.annotate(expr, f'{kind} uses generic operations (iterable has type "Any").') |
| 288 | elif isinstance(typ, Instance) and typ.type.fullname in ( |
| 289 | "typing.Iterable", |
| 290 | "typing.Iterator", |
| 291 | "typing.Sequence", |
| 292 | "typing.MutableSequence", |
| 293 | ): |
| 294 | self.annotate( |
| 295 | expr, |
| 296 | f'{kind} uses generic operations (iterable has the abstract type "{typ.type.fullname}").', |
| 297 | ) |
| 298 | |
| 299 | def visit_class_def(self, o: ClassDef, /) -> None: |
| 300 | super().visit_class_def(o) |
| 301 | if self.func_depth == 0: |
| 302 | # Don't complain about base classes at top level |
| 303 | for base in o.base_type_exprs: |
| 304 | self.ignored_lines.add(base.line) |
| 305 | |
| 306 | for s in o.defs.body: |
| 307 | if isinstance(s, AssignmentStmt): |
no outgoing calls
no test coverage detected
searching dependent graphs…