# Buggy code
def process_type_info(self, info: TypeInfo) -> None:
    # TODO: Additional things:
    # - declared_metaclass
    # - metaclass_type
    # - _promote
    # - typeddict_type
    # - replaced
    replace_nodes_in_symbol_table(info.names, self.replacements)
    for i, item in enumerate(info.mro):
        info.mro[i] = self.fixup(info.mro[i])
    for i, base in enumerate(info.bases):
        self.fixup_type(info.bases[i])
    if info.tuple_type:
        self.fixup_type(info.tuple_type)


# Traceback (AttributeError)
Traceback (most recent call last):
File "[somewhere]/mypy/dmypy_server.py", line 135, in serve
resp = self.run_command(command, data)
File "[somewhere]/mypy/dmypy_server.py", line 169, in run_command
return method(self, **data)
File "[somewhere]/mypy/dmypy_server.py", line 200, in cmd_check
return self.check(self.last_sources)
File "[somewhere]/mypy/dmypy_server.py", line 214, in check
return self.check_fine_grained(sources)
File "[somewhere]/mypy/dmypy_server.py", line 246, in check_fine_grained
return self.initialize_fine_grained(sources)
File "[somewhere]/mypy/dmypy_server.py", line 291, in initialize_fine_grained
messages = self.fine_grained_manager.update(changed)
File "[somewhere]/mypy/server/update.py", line 222, in update
result = self.update_single(next_id, next_path)
File "[somewhere]/mypy/server/update.py", line 264, in update_single
result = update_single_isolated(module, path, manager, previous_modules)
File "[somewhere]/mypy/server/update.py", line 437, in update_single_isolated
replace_modules_with_new_variants(manager, graph, old_modules, new_modules)
File "[somewhere]/mypy/server/update.py", line 702, in replace_modules_with_new_variants
new_module, new_module.names)
File "[somewhere]/mypy/server/astmerge.py", line 85, in merge_asts
node = replace_nodes_in_ast(new, replacement_map)
File "[somewhere]/mypy/server/astmerge.py", line 130, in replace_nodes_in_ast
node.accept(visitor)
File "[somewhere]/mypy/nodes.py", line 230, in accept
return visitor.visit_mypy_file(self)
File "[somewhere]/mypy/server/astmerge.py", line 151, in visit_mypy_file
super().visit_mypy_file(node)
File "[somewhere]/mypy/traverser.py", line 30, in visit_mypy_file
d.accept(self)
File "[somewhere]/mypy/nodes.py", line 931, in accept
return visitor.visit_if_stmt(self)
File "[somewhere]/mypy/traverser.py", line 114, in visit_if_stmt
o.else_body.accept(self)
File "[somewhere]/mypy/nodes.py", line 766, in accept
return visitor.visit_block(self)
File "[somewhere]/mypy/server/astmerge.py", line 154, in visit_block
super().visit_block(node)
File "[somewhere]/mypy/traverser.py", line 34, in visit_block
s.accept(self)
File "[somewhere]/mypy/nodes.py", line 704, in accept
return visitor.visit_class_def(self)
File "[somewhere]/mypy/server/astmerge.py", line 176, in visit_class_def
self.process_type_info(node.info)
File "[somewhere]/mypy/server/astmerge.py", line 264, in process_type_info
replace_nodes_in_symbol_table(info.names, self.replacements)
AttributeError: 'NoneType' object has no attribute 'names'

# Fixed code
def process_type_info(self, info: Optional[TypeInfo]) -> None:
    if info is None:
        return
    # TODO: Additional things:
    # - declared_metaclass
    # - metaclass_type
    # - _promote
    # - typeddict_type
    # - replaced
    replace_nodes_in_symbol_table(info.names, self.replacements)
    for i, item in enumerate(info.mro):
        info.mro[i] = self.fixup(info.mro[i])
    for i, base in enumerate(info.bases):
        self.fixup_type(info.bases[i])
    if info.tuple_type:
        self.fixup_type(info.tuple_type)