mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[InterfaceGen] Print abstract accessors in protocols (#19379)
* [InterfaceGen] Print abstract accessors in protocols This patch slightly cleans up printing accessors and ensures we print accessors abstractly in protocol context for textual interfaces. It also removes some assuptions around the FunctionBody callback and makes them more explicit. * Print getter and setter for didSet decls * Test _read and _modify * Fix logic for skipping willSet/didSet * Update 'final' test for new getter printing behavior
This commit is contained in:
@@ -135,13 +135,32 @@ struct PrintOptions {
|
|||||||
/// \brief Whether to print *any* accessors on properties.
|
/// \brief Whether to print *any* accessors on properties.
|
||||||
bool PrintPropertyAccessors = true;
|
bool PrintPropertyAccessors = true;
|
||||||
|
|
||||||
/// \brief Whether to print the accessors of a property abstractly,
|
/// Whether to print the accessors of a property abstractly,
|
||||||
/// i.e. always as get and set rather than the specific accessors
|
/// i.e. always as:
|
||||||
/// actually used to implement the property.
|
/// ```
|
||||||
|
/// var x: Int { get set }
|
||||||
|
/// ```
|
||||||
|
/// rather than the specific accessors actually used to implement the
|
||||||
|
/// property.
|
||||||
///
|
///
|
||||||
/// Printing function definitions takes priority over this setting.
|
/// Printing function definitions takes priority over this setting.
|
||||||
bool AbstractAccessors = true;
|
bool AbstractAccessors = true;
|
||||||
|
|
||||||
|
/// Whether to print a property with only a single getter using the shorthand
|
||||||
|
/// ```
|
||||||
|
/// var x: Int { return y }
|
||||||
|
/// ```
|
||||||
|
/// vs.
|
||||||
|
/// ```
|
||||||
|
/// var x: Int {
|
||||||
|
/// get { return y }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
bool CollapseSingleGetterProperty = true;
|
||||||
|
|
||||||
|
/// Whether to print the bodies of accessors in protocol context.
|
||||||
|
bool PrintAccessorBodiesInProtocols = false;
|
||||||
|
|
||||||
/// \brief Whether to print type definitions.
|
/// \brief Whether to print type definitions.
|
||||||
bool TypeDefinitions = false;
|
bool TypeDefinitions = false;
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ PrintOptions PrintOptions::printTextualInterfaceFile() {
|
|||||||
result.FullyQualifiedTypes = true;
|
result.FullyQualifiedTypes = true;
|
||||||
result.SkipImports = true;
|
result.SkipImports = true;
|
||||||
result.OmitNameOfInaccessibleProperties = true;
|
result.OmitNameOfInaccessibleProperties = true;
|
||||||
|
result.FunctionDefinitions = true;
|
||||||
|
result.CollapseSingleGetterProperty = false;
|
||||||
|
|
||||||
result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) {
|
result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) {
|
||||||
auto AFD = dyn_cast<AbstractFunctionDecl>(decl);
|
auto AFD = dyn_cast<AbstractFunctionDecl>(decl);
|
||||||
@@ -1579,15 +1581,15 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbstractAccessors is suppressed by FunctionDefinitions, but not the
|
// AbstractAccessors is suppressed by FunctionDefinitions.
|
||||||
// presence of an FunctionBody callback.
|
|
||||||
bool PrintAbstract =
|
bool PrintAbstract =
|
||||||
Options.AbstractAccessors && !Options.FunctionDefinitions;
|
Options.AbstractAccessors && !Options.FunctionDefinitions;
|
||||||
|
|
||||||
// We sometimes want to print the accessors abstractly
|
// We sometimes want to print the accessors abstractly
|
||||||
// instead of listing out how they're actually implemented.
|
// instead of listing out how they're actually implemented.
|
||||||
bool inProtocol = isa<ProtocolDecl>(ASD->getDeclContext());
|
bool inProtocol = isa<ProtocolDecl>(ASD->getDeclContext());
|
||||||
if (!Options.FunctionBody && (inProtocol || PrintAbstract)) {
|
if ((inProtocol && !Options.PrintAccessorBodiesInProtocols) ||
|
||||||
|
PrintAbstract) {
|
||||||
bool mutatingGetter = ASD->getGetter() && ASD->isGetterMutating();
|
bool mutatingGetter = ASD->getGetter() && ASD->isGetterMutating();
|
||||||
bool settable = ASD->isSettable(nullptr);
|
bool settable = ASD->isSettable(nullptr);
|
||||||
bool nonmutatingSetter = false;
|
bool nonmutatingSetter = false;
|
||||||
@@ -1650,12 +1652,13 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, print all the concrete defining accessors.
|
// Otherwise, print all the concrete defining accessors.
|
||||||
|
bool PrintAccessorBody = Options.FunctionDefinitions;
|
||||||
|
|
||||||
bool PrintAccessorBody = Options.FunctionDefinitions || Options.FunctionBody;
|
// Helper to print an accessor. Returns true if the
|
||||||
|
// accessor was present but skipped.
|
||||||
auto PrintAccessor = [&](AccessorDecl *Accessor) {
|
auto PrintAccessor = [&](AccessorDecl *Accessor) -> bool {
|
||||||
if (!Accessor)
|
if (!Accessor || !shouldPrint(Accessor))
|
||||||
return;
|
return true;
|
||||||
if (!PrintAccessorBody) {
|
if (!PrintAccessorBody) {
|
||||||
if (isAccessorAssumedNonMutating(Accessor->getAccessorKind())) {
|
if (isAccessorAssumedNonMutating(Accessor->getAccessorKind())) {
|
||||||
if (Accessor->isMutating()) {
|
if (Accessor->isMutating()) {
|
||||||
@@ -1679,19 +1682,17 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
|
|||||||
indent();
|
indent();
|
||||||
Printer.printNewline();
|
Printer.printNewline();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((PrintAbstract ||
|
// Determine if we should print the getter without the 'get { ... }'
|
||||||
(impl.getReadImpl() == ReadImplKind::Get && ASD->getGetter())) &&
|
// block around it.
|
||||||
!ASD->supportsMutation() && !ASD->isGetterMutating() &&
|
bool isOnlyGetter = impl.getReadImpl() == ReadImplKind::Get &&
|
||||||
PrintAccessorBody && !Options.FunctionDefinitions) {
|
ASD->getGetter();
|
||||||
// Omit the 'get' keyword. Directly print getter
|
bool isGetterMutating = ASD->supportsMutation() || ASD->isGetterMutating();
|
||||||
if (auto BodyFunc = Options.FunctionBody) {
|
if (isOnlyGetter && !isGetterMutating && PrintAccessorBody &&
|
||||||
BodyFunc(ASD->getGetter(), Printer);
|
Options.FunctionBody && Options.CollapseSingleGetterProperty) {
|
||||||
indent();
|
Options.FunctionBody(ASD->getGetter(), Printer);
|
||||||
return;
|
|
||||||
}
|
|
||||||
Printer.printNewline();
|
|
||||||
indent();
|
indent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1726,10 +1727,15 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
|
|||||||
case WriteImplKind::Stored:
|
case WriteImplKind::Stored:
|
||||||
llvm_unreachable("simply-stored variable should have been filtered out");
|
llvm_unreachable("simply-stored variable should have been filtered out");
|
||||||
case WriteImplKind::StoredWithObservers:
|
case WriteImplKind::StoredWithObservers:
|
||||||
case WriteImplKind::InheritedWithObservers:
|
case WriteImplKind::InheritedWithObservers: {
|
||||||
PrintAccessor(ASD->getWillSetFunc());
|
bool skippedWillSet = PrintAccessor(ASD->getWillSetFunc());
|
||||||
PrintAccessor(ASD->getDidSetFunc());
|
bool skippedDidSet = PrintAccessor(ASD->getDidSetFunc());
|
||||||
|
if (skippedDidSet && skippedWillSet) {
|
||||||
|
PrintAccessor(ASD->getGetter());
|
||||||
|
PrintAccessor(ASD->getSetter());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case WriteImplKind::Set:
|
case WriteImplKind::Set:
|
||||||
PrintAccessor(ASD->getSetter());
|
PrintAccessor(ASD->getSetter());
|
||||||
if (!shouldHideModifyAccessor())
|
if (!shouldHideModifyAccessor())
|
||||||
@@ -1751,9 +1757,6 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
|
|||||||
|
|
||||||
Printer << "}";
|
Printer << "}";
|
||||||
|
|
||||||
if (!PrintAbstract)
|
|
||||||
Printer.printNewline();
|
|
||||||
|
|
||||||
indent();
|
indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2397,6 +2397,8 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
|
|||||||
Options.AccessFilter = AccessLevel::Private;
|
Options.AccessFilter = AccessLevel::Private;
|
||||||
Options.PrintAccess = false;
|
Options.PrintAccess = false;
|
||||||
Options.SkipAttributes = true;
|
Options.SkipAttributes = true;
|
||||||
|
Options.FunctionDefinitions = true;
|
||||||
|
Options.PrintAccessorBodiesInProtocols = true;
|
||||||
Options.FunctionBody = [&](const ValueDecl *VD, ASTPrinter &Printer) {
|
Options.FunctionBody = [&](const ValueDecl *VD, ASTPrinter &Printer) {
|
||||||
Printer << " {";
|
Printer << " {";
|
||||||
Printer.printNewline();
|
Printer.printNewline();
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
// CHECK: final public class FinalClass {
|
// CHECK: final public class FinalClass {
|
||||||
public final class FinalClass {
|
public final class FinalClass {
|
||||||
// CHECK: @inlinable final public class var a: [[INT:(Swift.)?Int]] {
|
// CHECK: @inlinable final public class var a: [[INT:(Swift.)?Int]] {
|
||||||
|
// CHECK-NEXT: {{^}} get {
|
||||||
// CHECK-NEXT: return 3
|
// CHECK-NEXT: return 3
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: }
|
||||||
@inlinable
|
@inlinable
|
||||||
public final class var a: Int {
|
public final class var a: Int {
|
||||||
return 3
|
return 3
|
||||||
|
|||||||
@@ -37,8 +37,10 @@ public struct Foo: Hashable {
|
|||||||
|
|
||||||
|
|
||||||
// CHECK: @_transparent public var transparent: [[INT]] {
|
// CHECK: @_transparent public var transparent: [[INT]] {
|
||||||
|
// CHECK-NEXT: get {
|
||||||
// CHECK-NEXT: return 34
|
// CHECK-NEXT: return 34
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: }
|
||||||
@_transparent
|
@_transparent
|
||||||
public var transparent: Int {
|
public var transparent: Int {
|
||||||
return 34
|
return 34
|
||||||
@@ -102,6 +104,78 @@ public struct Foo: Hashable {
|
|||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: @inlinable public var inlinableReadAndModify: [[INT]] {
|
||||||
|
@inlinable
|
||||||
|
public var inlinableReadAndModify: Int {
|
||||||
|
// CHECK: _read {
|
||||||
|
// CHECK-NEXT: yield 0
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
_read {
|
||||||
|
yield 0
|
||||||
|
}
|
||||||
|
// CHECK: _modify {
|
||||||
|
// CHECK-NEXT: var x = 0
|
||||||
|
// CHECK-NEXT: yield &x
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
_modify {
|
||||||
|
var x = 0
|
||||||
|
yield &x
|
||||||
|
}
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: public var inlinableReadNormalModify: [[INT]] {
|
||||||
|
public var inlinableReadNormalModify: Int {
|
||||||
|
// CHECK: @inlinable _read {
|
||||||
|
// CHECK-NEXT: yield 0
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
@inlinable _read {
|
||||||
|
yield 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: _modify{{$}}
|
||||||
|
// CHECK-NOT: var x = 0
|
||||||
|
// CHECK-NOT: yield &x
|
||||||
|
// CHECK-NOT: }
|
||||||
|
_modify {
|
||||||
|
var x = 0
|
||||||
|
yield &x
|
||||||
|
}
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: public var normalReadInlinableModify: [[INT]] {
|
||||||
|
public var normalReadInlinableModify: Int {
|
||||||
|
// CHECK: _read{{$}}
|
||||||
|
// CHECK-NOT: yield 0
|
||||||
|
// CHECK-NOT: }
|
||||||
|
_read {
|
||||||
|
yield 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: @inlinable _modify {
|
||||||
|
// CHECK-NEXT: var x = 0
|
||||||
|
// CHECK-NEXT: yield &x
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
@inlinable _modify {
|
||||||
|
var x = 0
|
||||||
|
yield &x
|
||||||
|
}
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: public var normalReadAndModify: [[INT]] {
|
||||||
|
public var normalReadAndModify: Int {
|
||||||
|
// CHECK-NEXT: _read{{$}}
|
||||||
|
_read { yield 0 }
|
||||||
|
// CHECK-NEXT: _modify{{$}}
|
||||||
|
_modify {
|
||||||
|
var x = 0
|
||||||
|
yield &x
|
||||||
|
}
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK: @inlinable public func inlinableMethod() {
|
// CHECK: @inlinable public func inlinableMethod() {
|
||||||
// CHECK-NOT: #if NO
|
// CHECK-NOT: #if NO
|
||||||
// CHECK-NOT: print("Hello, world!")
|
// CHECK-NOT: print("Hello, world!")
|
||||||
|
|||||||
Reference in New Issue
Block a user