Skip to content

Commit 151c9de

Browse files
committed
AST: Consolidate abstract/contrete syntax decl lookup functions.
1 parent 02dcd5d commit 151c9de

File tree

8 files changed

+69
-114
lines changed

8 files changed

+69
-114
lines changed

include/swift/AST/AvailabilityInference.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,6 @@ class AvailabilityInference {
9494
AvailabilityDomain &domain, llvm::VersionTuple &platformVer);
9595
};
9696

97-
// FIXME: This should become a utility on Decl.
98-
99-
/// Given a declaration upon which an availability attribute would appear in
100-
/// concrete syntax, return a declaration to which the parser
101-
/// actually attaches the attribute in the abstract syntax tree. We use this
102-
/// function to determine whether the concrete syntax already has an
103-
/// availability attribute.
104-
const Decl *abstractSyntaxDeclForAvailableAttribute(const Decl *D);
105-
10697
} // end namespace swift
10798

10899
#endif

include/swift/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,16 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
15101510
/// Returns true if this declaration has any `@backDeployed` attributes.
15111511
bool hasBackDeployedAttr() const;
15121512

1513+
/// Return the declaration upon which the attributes for this declaration
1514+
/// would appear in concrete syntax. This function is necessary because for
1515+
/// semantic analysis, the parser attaches attributes to declarations other
1516+
/// than those on which they, concretely, appear.
1517+
const Decl *getConcreteSyntaxDeclForAttributes() const;
1518+
1519+
/// Return the declaration to which the parser actually attaches attributes in
1520+
/// the abstract syntax tree (see `getConcreteSyntaxDeclForAttributes()`).
1521+
const Decl *getAbstractSyntaxDeclForAttributes() const;
1522+
15131523
/// Apply the specified function to decls that should be placed _next_ to
15141524
/// this decl when constructing AST.
15151525
void forEachDeclToHoist(llvm::function_ref<void(Decl *)> callback) const;

lib/AST/Availability.cpp

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ static std::optional<SemanticAvailableAttr>
383383
getDeclAvailableAttrForPlatformIntroduction(const Decl *D) {
384384
std::optional<SemanticAvailableAttr> bestAvailAttr;
385385

386-
D = abstractSyntaxDeclForAvailableAttribute(D);
386+
D = D->getAbstractSyntaxDeclForAttributes();
387387

388388
for (auto attr : D->getSemanticAvailableAttrs(/*includingInactive=*/false)) {
389389
if (!attr.isPlatformSpecific() || !attr.getIntroduced())
@@ -1054,36 +1054,6 @@ bool ASTContext::supportsVersionedAvailability() const {
10541054
return minimumAvailableOSVersionForTriple(LangOpts.Target).has_value();
10551055
}
10561056

1057-
// FIXME: Rename abstractSyntaxDeclForAvailableAttribute since it's useful
1058-
// for more attributes than `@available`.
1059-
const Decl *
1060-
swift::abstractSyntaxDeclForAvailableAttribute(const Decl *ConcreteSyntaxDecl) {
1061-
// This function needs to be kept in sync with its counterpart,
1062-
// concreteSyntaxDeclForAvailableAttribute().
1063-
1064-
if (auto *PBD = dyn_cast<PatternBindingDecl>(ConcreteSyntaxDecl)) {
1065-
// Existing @available attributes in the AST are attached to VarDecls
1066-
// rather than PatternBindingDecls, so we return the first VarDecl for
1067-
// the pattern binding declaration.
1068-
// This is safe, even though there may be multiple VarDecls, because
1069-
// all parsed attribute that appear in the concrete syntax upon on the
1070-
// PatternBindingDecl are added to all of the VarDecls for the pattern
1071-
// binding.
1072-
for (auto index : range(PBD->getNumPatternEntries())) {
1073-
if (auto VD = PBD->getAnchoringVarDecl(index))
1074-
return VD;
1075-
}
1076-
} else if (auto *ECD = dyn_cast<EnumCaseDecl>(ConcreteSyntaxDecl)) {
1077-
// Similar to the PatternBindingDecl case above, we return the
1078-
// first EnumElementDecl.
1079-
if (auto *Elem = ECD->getFirstElement()) {
1080-
return Elem;
1081-
}
1082-
}
1083-
1084-
return ConcreteSyntaxDecl;
1085-
}
1086-
10871057
bool swift::isExported(const Decl *D) {
10881058
if (auto *VD = dyn_cast<ValueDecl>(D)) {
10891059
return isExported(VD);

lib/AST/AvailabilityConstraint.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ swift::getAvailabilityConstraintsForDecl(const Decl *decl,
232232
if (isa<GenericTypeParamDecl>(decl))
233233
return DeclAvailabilityConstraints();
234234

235-
decl = abstractSyntaxDeclForAvailableAttribute(decl);
235+
decl = decl->getAbstractSyntaxDeclForAttributes();
236236

237237
getAvailabilityConstraintsForDecl(constraints, decl, context);
238238

lib/AST/AvailabilityScopeBuilder.cpp

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ using namespace swift;
3434
/// that is active.
3535
// FIXME: [availability] De-duplicate this with TypeCheckAvailability.cpp.
3636
static bool hasActiveAvailableAttribute(const Decl *decl, ASTContext &ctx) {
37-
decl = abstractSyntaxDeclForAvailableAttribute(decl);
37+
decl = decl->getAbstractSyntaxDeclForAttributes();
3838

3939
for (auto attr : decl->getSemanticAvailableAttrs()) {
4040
if (attr.isActive(ctx))
@@ -50,36 +50,6 @@ static bool computeContainedByDeploymentTarget(AvailabilityScope *scope,
5050
AvailabilityRange::forDeploymentTarget(ctx));
5151
}
5252

53-
/// Given a declaration that allows availability attributes in the abstract
54-
/// syntax tree, return the declaration upon which the declaration would
55-
/// appear in concrete syntax. This function is necessary because for semantic
56-
/// analysis, the parser attaches attributes to declarations other
57-
/// than those on which they, concretely, appear. For these declarations (enum
58-
/// cases and variable declarations) a Fix-It for an added availability
59-
/// attribute should be suggested for the appropriate concrete location.
60-
// FIXME: [availability] De-duplicate this with TypeCheckAvailability.cpp.
61-
static const Decl *
62-
concreteSyntaxDeclForAvailableAttribute(const Decl *abstractSyntaxDecl) {
63-
// This function needs to be kept in sync with its counterpart,
64-
// abstractSyntaxDeclForAvailableAttribute().
65-
66-
// The source range for VarDecls does not include 'var ' (and, in any
67-
// event, multiple variables can be introduced with a single 'var'),
68-
// so suggest adding an attribute to the PatterningBindingDecl instead.
69-
if (auto *vd = dyn_cast<VarDecl>(abstractSyntaxDecl)) {
70-
if (auto *pbd = vd->getParentPatternBinding())
71-
return pbd;
72-
}
73-
74-
// Similarly suggest applying the Fix-It to the parent enum case rather than
75-
// the enum element.
76-
if (auto *ee = dyn_cast<EnumElementDecl>(abstractSyntaxDecl)) {
77-
return ee->getParentCase();
78-
}
79-
80-
return abstractSyntaxDecl;
81-
}
82-
8353
namespace {
8454
/// A class that walks the AST to build the availability scope tree.
8555
class AvailabilityScopeBuilder : private ASTWalker {
@@ -282,7 +252,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
282252
bool shouldSkipDecl(Decl *decl) const {
283253
// Only visit a node that has a corresponding concrete syntax node if we are
284254
// already walking that concrete syntax node.
285-
auto *concreteDecl = concreteSyntaxDeclForAvailableAttribute(decl);
255+
auto *concreteDecl = decl->getConcreteSyntaxDeclForAttributes();
286256
if (concreteDecl != decl) {
287257
if (ConcreteDeclStack.empty() || ConcreteDeclStack.back() != concreteDecl)
288258
return true;
@@ -323,7 +293,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
323293

324294
// If this decl is the concrete syntax decl for some abstract syntax decl,
325295
// push it onto the stack so that the abstract syntax decls may be visited.
326-
auto *abstractDecl = abstractSyntaxDeclForAvailableAttribute(decl);
296+
auto *abstractDecl = decl->getAbstractSyntaxDeclForAttributes();
327297
if (abstractDecl != decl) {
328298
ConcreteDeclStack.push_back(decl);
329299
}
@@ -425,7 +395,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
425395

426396
// Don't introduce for abstract syntax nodes that have separate concrete
427397
// syntax nodes. The scope will be introduced for the concrete node instead.
428-
if (concreteSyntaxDeclForAvailableAttribute(decl) != decl)
398+
if (decl->getConcreteSyntaxDeclForAttributes() != decl)
429399
return nullptr;
430400

431401
// Declarations with explicit availability attributes always get a scope.
@@ -456,7 +426,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
456426
auto effectiveIntroduction = AvailabilityRange::alwaysAvailable();
457427

458428
// Availability attributes are found abstract syntax decls.
459-
decl = abstractSyntaxDeclForAvailableAttribute(decl);
429+
decl = decl->getAbstractSyntaxDeclForAttributes();
460430

461431
// As a special case, extension decls are treated as effectively as
462432
// available as the nominal type they extend, up to the deployment target.

lib/AST/Decl.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,54 @@ bool Decl::hasBackDeployedAttr() const {
634634
return false;
635635
}
636636

637+
const Decl *Decl::getConcreteSyntaxDeclForAttributes() const {
638+
// This function needs to be kept in sync with its counterpart,
639+
// getAbstractSyntaxDeclForAttributes().
640+
641+
// The source range for VarDecls does not include 'var ' (and, in any
642+
// event, multiple variables can be introduced with a single 'var'),
643+
// so suggest adding an attribute to the PatterningBindingDecl instead.
644+
if (auto *vd = dyn_cast<VarDecl>(this)) {
645+
if (auto *pbd = vd->getParentPatternBinding())
646+
return pbd;
647+
}
648+
649+
// Similarly suggest applying the Fix-It to the parent enum case rather than
650+
// the enum element.
651+
if (auto *ee = dyn_cast<EnumElementDecl>(this)) {
652+
return ee->getParentCase();
653+
}
654+
655+
return this;
656+
}
657+
658+
const Decl *Decl::getAbstractSyntaxDeclForAttributes() const {
659+
// This function needs to be kept in sync with its counterpart,
660+
// getConcreteSyntaxDeclForAttributes().
661+
662+
if (auto *pbd = dyn_cast<PatternBindingDecl>(this)) {
663+
// @available attributes in the AST are attached to VarDecls
664+
// rather than PatternBindingDecls, so we return the first VarDecl for
665+
// the pattern binding declaration.
666+
// This is safe, even though there may be multiple VarDecls, because
667+
// all parsed attribute that appear in the concrete syntax upon on the
668+
// PatternBindingDecl are added to all of the VarDecls for the pattern
669+
// binding.
670+
for (auto index : range(pbd->getNumPatternEntries())) {
671+
if (auto vd = pbd->getAnchoringVarDecl(index))
672+
return vd;
673+
}
674+
} else if (auto *ecd = dyn_cast<EnumCaseDecl>(this)) {
675+
// Similar to the PatternBindingDecl case above, we return the
676+
// first EnumElementDecl.
677+
if (auto *element = ecd->getFirstElement()) {
678+
return element;
679+
}
680+
}
681+
682+
return this;
683+
}
684+
637685
void Decl::forEachDeclToHoist(llvm::function_ref<void(Decl *)> callback) const {
638686
switch (getKind()) {
639687
case DeclKind::TopLevelCode: {

lib/AST/Module.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#include "swift/AST/ASTWalker.h"
2222
#include "swift/AST/AccessScope.h"
2323
#include "swift/AST/AttrKind.h"
24-
#include "swift/AST/AvailabilityInference.h"
2524
#include "swift/AST/Builtins.h"
2625
#include "swift/AST/ClangModuleLoader.h"
2726
#include "swift/AST/DiagnosticsSema.h"
@@ -3159,7 +3158,7 @@ bool Decl::isSPI() const {
31593158
}
31603159

31613160
ArrayRef<Identifier> Decl::getSPIGroups() const {
3162-
const Decl *D = abstractSyntaxDeclForAvailableAttribute(this);
3161+
const Decl *D = getAbstractSyntaxDeclForAttributes();
31633162

31643163
if (!isa<ValueDecl>(D) &&
31653164
!isa<ExtensionDecl>(D))

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@
5252
#include "llvm/Support/SaveAndRestore.h"
5353
using namespace swift;
5454

55-
// FIXME: [availability] De-duplicate this with AvailabilityScopeBuilder.cpp.
56-
static const Decl *
57-
concreteSyntaxDeclForAvailableAttribute(const Decl *AbstractSyntaxDecl);
58-
5955
/// Emit a diagnostic for references to declarations that have been
6056
/// marked as unavailable, either through "unavailable" or "obsoleted:".
6157
static bool diagnoseExplicitUnavailability(
@@ -249,7 +245,7 @@ ExportContext::getExportabilityReason() const {
249245
/// that is active.
250246
// FIXME: [availability] De-duplicate this with AvailabilityScopeBuilder.cpp.
251247
static bool hasActiveAvailableAttribute(const Decl *D, ASTContext &ctx) {
252-
D = abstractSyntaxDeclForAvailableAttribute(D);
248+
D = D->getAbstractSyntaxDeclForAttributes();
253249

254250
for (auto Attr : D->getSemanticAvailableAttrs()) {
255251
if (Attr.isActive(ctx))
@@ -545,35 +541,6 @@ static const Decl *findContainingDeclaration(SourceRange ReferenceRange,
545541
return nullptr;
546542
}
547543

548-
/// Given a declaration that allows availability attributes in the abstract
549-
/// syntax tree, return the declaration upon which the declaration would
550-
/// appear in concrete syntax. This function is necessary because for semantic
551-
/// analysis, the parser attaches attributes to declarations other
552-
/// than those on which they, concretely, appear. For these declarations (enum
553-
/// cases and variable declarations) a Fix-It for an added availability
554-
/// attribute should be suggested for the appropriate concrete location.
555-
static const Decl *
556-
concreteSyntaxDeclForAvailableAttribute(const Decl *AbstractSyntaxDecl) {
557-
// This function needs to be kept in sync with its counterpart,
558-
// abstractSyntaxDeclForAvailableAttribute().
559-
560-
// The source range for VarDecls does not include 'var ' (and, in any
561-
// event, multiple variables can be introduced with a single 'var'),
562-
// so suggest adding an attribute to the PatterningBindingDecl instead.
563-
if (auto *VD = dyn_cast<VarDecl>(AbstractSyntaxDecl)) {
564-
if (auto *PBD = VD->getParentPatternBinding())
565-
return PBD;
566-
}
567-
568-
// Similarly suggest applying the Fix-It to the parent enum case rather than
569-
// the enum element.
570-
if (auto *EE = dyn_cast<EnumElementDecl>(AbstractSyntaxDecl)) {
571-
return EE->getParentCase();
572-
}
573-
574-
return AbstractSyntaxDecl;
575-
}
576-
577544
/// Given a declaration, return a better related declaration for which
578545
/// to suggest an @available fixit, or the original declaration
579546
/// if no such related declaration exists.
@@ -584,7 +551,7 @@ static const Decl *relatedDeclForAvailabilityFixit(const Decl *D) {
584551
D = accessor->getStorage();
585552
}
586553

587-
return abstractSyntaxDeclForAvailableAttribute(D);
554+
return D->getAbstractSyntaxDeclForAttributes();
588555
}
589556

590557
/// Walk the DeclContext hierarchy starting from D to find a declaration
@@ -749,7 +716,7 @@ static void fixAvailabilityForDecl(
749716
// syntax to suggest the Fix-It may differ from the declaration to which
750717
// we attach availability attributes in the abstract syntax tree during
751718
// parsing.
752-
const Decl *ConcDecl = concreteSyntaxDeclForAvailableAttribute(D);
719+
const Decl *ConcDecl = D->getConcreteSyntaxDeclForAttributes();
753720

754721
// To avoid exposing the pattern binding declaration to the user, get the
755722
// descriptive kind from one of the VarDecls.

0 commit comments

Comments
 (0)