Skip to content

ASTPrinter: print public inherited protocols of the skipped private protocols #38882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5742,10 +5742,9 @@ swift::getInheritedForPrinting(

// Collect synthesized conformances.
auto &ctx = decl->getASTContext();
llvm::SetVector<ProtocolDecl *> protocols;
for (auto attr : decl->getAttrs().getAttributes<SynthesizedProtocolAttr>()) {
if (auto *proto = ctx.getProtocol(attr->getProtocolKind())) {
if (!options.shouldPrint(proto))
continue;
// The SerialExecutor conformance is only synthesized on the root
// actor class, so we can just test resilience immediately.
if (proto->isSpecificProtocol(KnownProtocolKind::SerialExecutor) &&
Expand All @@ -5755,9 +5754,28 @@ swift::getInheritedForPrinting(
isa<EnumDecl>(decl) &&
cast<EnumDecl>(decl)->hasRawType())
continue;
Results.push_back({TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
/*isUnchecked=*/false});
protocols.insert(proto);
}
}

for (size_t i = 0; i < protocols.size(); i++) {
auto proto = protocols[i];

if (!options.shouldPrint(proto)) {
// If private stdlib protocols are skipped and this is a private stdlib
// protocol, see if any of its inherited protocols are public. Those
// protocols can affect the user-visible behavior of the declaration, and
// should be printed.
if (options.SkipPrivateStdlibDecls &&
proto->isPrivateStdlibDecl(!options.SkipUnderscoredStdlibProtocols)) {
auto inheritedProtocols = proto->getInheritedProtocols();
protocols.insert(inheritedProtocols.begin(), inheritedProtocols.end());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that one of these protocols would be hidden?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in that case we'll just skip it on L5764. This actually happens with the NSError types: they are imported with a conformance to _BridgedStoredNSError (hidden), which inherits from _ObjectiveCBridgeableError (also hidden), so this logic will look into the parent protocol of _ObjectiveCBridgeableError, which is Error, and the conformance to Error will be printed.

}
continue;
}

Results.push_back({TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
/*isUnchecked=*/false});
}
}

Expand Down
29 changes: 22 additions & 7 deletions test/ClangImporter/enum-error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// RUN: echo '#include "enum-error.h"' > %t.m
// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/enum-error.h -import-objc-header %S/Inputs/enum-error.h -print-regular-comments --cc-args %target-cc-options -fsyntax-only %t.m -I %S/Inputs > %t.txt
// RUN: %FileCheck -check-prefix=HEADER %s < %t.txt
// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/enum-error.h -import-objc-header %S/Inputs/enum-error.h -print-regular-comments --skip-private-stdlib-decls -skip-underscored-stdlib-protocols --cc-args %target-cc-options -fsyntax-only %t.m -I %S/Inputs > %t2.txt
// RUN: %FileCheck -check-prefix=HEADER-NO-PRIVATE %s < %t2.txt

import Foundation

Expand Down Expand Up @@ -121,12 +123,25 @@ class ObjCTest {
}
#endif

// HEADER: enum Code : Int32, _ErrorCodeProtocol {
// HEADER: init?(rawValue: Int32)
// HEADER: var rawValue: Int32 { get }
// HEADER: typealias _ErrorType = TestError
// HEADER: case TENone
// HEADER: case TEOne
// HEADER: case TETwo
// HEADER: struct TestError : _BridgedStoredNSError {
// HEADER: enum Code : Int32, _ErrorCodeProtocol {
// HEADER: init?(rawValue: Int32)
// HEADER: var rawValue: Int32 { get }
// HEADER: typealias _ErrorType = TestError
// HEADER: case TENone
// HEADER: case TEOne
// HEADER: case TETwo
// HEADER: }
// HEADER: }
// HEADER: func getErr() -> TestError.Code

// HEADER-NO-PRIVATE: struct TestError : CustomNSError, Hashable, Error {
// HEADER-NO-PRIVATE: enum Code : Int32, Equatable {
// HEADER-NO-PRIVATE: init?(rawValue: Int32)
// HEADER-NO-PRIVATE: var rawValue: Int32 { get }
// HEADER-NO-PRIVATE: typealias _ErrorType = TestError
// HEADER-NO-PRIVATE: case TENone
// HEADER-NO-PRIVATE: case TEOne
// HEADER-NO-PRIVATE: case TETwo
// HEADER-NO-PRIVATE: }
// HEADER-NO-PRIVATE: }
4 changes: 2 additions & 2 deletions test/SourceKit/DocSupport/doc_error_domain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// RUN: -sdk %sdk | %sed_clean > %t.response
// RUN: %FileCheck -input-file=%t.response %s

// CHECK: struct MyError {
// CHECK: enum Code : Int32 {
// CHECK: struct MyError : CustomNSError, Hashable, Error {
// CHECK: enum Code : Int32, Equatable {
// CHECK: case errFirst
// CHECK: case errSecond
// CHECK: }
Expand Down