Repository: apple/swift
File: lib/AST/ASTPrinter.cpp (C++)

Code before:
    return false;

  auto nonSendable = NTD->getAttrs().getEffectiveSendableAttr();
  if (!isa_and_nonnull<NonSendableAttr>(nonSendable))
    return false;

  // GetImplicitSendableRequest::evaluate() creates its extension with the
  // attribute's AtLoc, so this is a good way to quickly check if the extension
  // was synthesized for an '@_nonSendable' attribute.
  return ED->getLocFromSource() == nonSendable->AtLoc;
}

bool ShouldPrintChecker::shouldPrint(const Decl *D,
                                     const PrintOptions &Options) {
  // Skip constructors that reference not directly imported modules
  if (auto *CD = dyn_cast<ConstructorDecl>(D)) {
    if (Options.IsForSwiftInterface && Options.CurrentModule) {
      for (auto *param : *CD->getParameters()) {
        Type paramType = param->getInterfaceType();
        // Helper to check if a nominal type is from an implementation-only module
        auto isFromImplementationOnlyModule = [&](Type t) -> bool {
          if (auto *nominal = t->getAnyNominal()) {
            ModuleDecl *typeModule = nominal->getModuleContext();
            if (typeModule && typeModule != Options.CurrentModule &&
                !typeModule->isSystemModule()) {
              return Options.CurrentModule->isImportedImplementationOnly(typeModule);
            }
          }
          return false;
        };
        // Check the direct type
        if (isFromImplementationOnlyModule(paramType)) {
          return false;
        }
        // Check generic type arguments (like Optional<T>, Array<T>)
        if (auto *boundGeneric = paramType->getAs<BoundGenericType>()) {
          for (Type genericArg : boundGeneric->getGenericArgs()) {
            if (isFromImplementationOnlyModule(genericArg)) {
              return false;
            }
          }
        }
      }
    }
  }

  if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
    if (Options.printExtensionContentAsMembers(ED))
      return false;
  }


Review comment (suggestion):
We should check for other ways of hiding a module beyond implementation-only, and likely the different swiftinterfaces. There's not a central service for this already in the ASTPrinted as we do most of this work at the type-checker level, we may need to add one.

For the source of truth the services on SourceFile may be the best option, `getRestrictedImportKind` and `getImportAccessLevel` should list the possible hiding behaviors:
- `RestrictedImportKind::MissingImport` and `ImplementationOnly` hide in all swiftinterface kinds.
- `RestrictedImportKind::SPIOnly` hides only in the public swiftinterface.
- If not already hidden we should check for `getImportAccessLevel`.
   - Internal and below hide in all swiftinterfaces.
   - Package hides only in public and private swiftinterfaces, it's still printed in the package swiftinterface.
   - Otherwise it's printed.

Code after:
    return false;

  auto nonSendable = NTD->getAttrs().getEffectiveSendableAttr();
  if (!isa_and_nonnull<NonSendableAttr>(nonSendable))
    return false;

  // GetImplicitSendableRequest::evaluate() creates its extension with the
  // attribute's AtLoc, so this is a good way to quickly check if the extension
  // was synthesized for an '@_nonSendable' attribute.
  return ED->getLocFromSource() == nonSendable->AtLoc;
}

bool ShouldPrintChecker::shouldPrint(const Decl *D,
                                     const PrintOptions &Options) {
  // Skip constructors defined in Objective-C categories that are not
  // publicly imported according to the interface type being generated
  if (auto *CD = dyn_cast<ConstructorDecl>(D)) {
    if (CD->isImplicit() && Options.IsForSwiftInterface &&
        Options.CurrentModule) {
      // For inherited constructors, check the original declaration
      auto *checkDecl = CD;
      if (auto *overridden = CD->getOverriddenDecl()) {
        checkDecl = overridden;
      }
      auto definingModule = checkDecl->getModuleContext();
      // Check how the defining module is imported
      if (auto *SF = CD->getDeclContext()->getParentSourceFile()) {
        // Don't check import status for self-imports
        if (definingModule != SF->getParentModule()) {
          auto restrictedKind = SF->getRestrictedImportKind(definingModule);
          switch (restrictedKind) {
          // MissingImport and ImplementationOnly: skip in all interfaces
          case RestrictedImportKind::MissingImport:
          case RestrictedImportKind::ImplementationOnly:
            return false;
          // SPIOnly: skip in public interfaces
          case RestrictedImportKind::SPIOnly:
            if (Options.printPublicInterface())
              return false;
            break;
          case RestrictedImportKind::None:
            break;
          }
          // Check access level
          if (auto importAccess = SF->getImportAccessLevel(definingModule)) {
            auto accessLevel = importAccess->accessLevel;
            switch (accessLevel) {
            // Internal and below: skip in all interfaces
            case AccessLevel::Private:
            case AccessLevel::FilePrivate:
            case AccessLevel::Internal: