docs: def generate_stub(self):
          """Generate the stub code for this source.
  
          :sig: () -> str
          :return: Generated stub code.
          """
          needed_types = self.required_types - BUILTIN_TYPES
  
          needed_types -= self.defined_types
          _logger.debug("defined types: %s", self.defined_types)
  
          module_vars = {v.name for v in self.root.variables}
          _logger.debug("module variables: %s", module_vars)
  
          qualified_types = {n for n in needed_types if "." in n}
          qualified_namespaces = {".".join(n.split(".")[:-1]) for n in qualified_types}
  
          needed_namespaces = qualified_namespaces - module_vars
          needed_types -= qualified_types
          _logger.debug("needed namespaces: %s", needed_namespaces)
  
          imported_names = {n.split("::")[0] for n in self.imported_names}
          imported_types = imported_names & (needed_types | needed_namespaces)
          needed_types -= imported_types
          needed_namespaces -= imported_names
          _logger.debug("used imported types: %s", imported_types)
  
          try:
              typing_mod = __import__("typing")
              typing_types = {n for n in needed_types if hasattr(typing_mod, n)}
              needed_types -= typing_types
              _logger.debug("types from typing module: %s", typing_types)
          except ImportError:
              typing_types = set()
              _logger.warn("typing module not installed")
  
          if len(needed_types) > 0:
              raise ValueError("Unknown types: " + ", ".join(needed_types))
  
          out = StringIO()
          started = False
  
          if len(typing_types) > 0:
              line = self.generate_import_from("typing", typing_types)
              out.write(line + "\n")
              started = True
  
          if len(imported_types) > 0:
              if started:
                  out.write("\n")
              # preserve the import order in the source file
              for name in self.imported_names:
                  if name.split("::")[0] in imported_types:
                      line = self.generate_import_from(self.imported_names[name], {name})
                      out.write(line + "\n")
              started = True
  
          if len(needed_namespaces) > 0:
              if started:
                  out.write("\n")
              as_names = {n.split("::")[0]: n for n in self.imported_namespaces if "::" in n}
              for module_ in sorted(needed_namespaces):
                  if module_ in as_names:
                      a, n = as_names[module_].split("::")
                      out.write("import " + n + " as " + a + "\n")
                  else:
                      out.write("import " + module_ + "\n")
              started = True
  
          if len(self.aliases) > 0:
              if started:
                  out.write("\n")
              for alias, signature in self.aliases.items():
                  out.write("%s = %s\n" % (alias, signature))
              started = True
  
          if started:
              out.write("\n")
          stub_lines = self.root.get_code()
          n_lines = len(stub_lines)
          for line_no in range(n_lines):
              prev_line = stub_lines[line_no - 1] if line_no > 0 else None
              line = stub_lines[line_no]
              next_line = stub_lines[line_no + 1] if line_no < (n_lines - 1) else None
              if (
                  line.startswith("class ")
                  and (prev_line is not None)
                  and (
                      (not prev_line.startswith("class "))
                      or (next_line and next_line.startswith(" "))
                  )
              ):
                  out.write("\n")
              if (
                  line.startswith("def ")
                  and (prev_line is not None)
                  and (prev_line.startswith((" ", "class ")))
              ):
                  out.write("\n")
              out.write(line + "\n")
              line_no += 1
          return out.getvalue()