Skip to content

Commit a0052c9

Browse files
author
Nathan Hawes
authored
Merge pull request #25758 from nathawes/property-wrapper-rename
[IDE][Index] Property wrapper rename support
2 parents 8f15eb0 + e08a6c1 commit a0052c9

32 files changed

+1172
-109
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ struct PrintOptions {
299299
/// Empty means allow all.
300300
std::vector<AnyAttrKind> ExclusiveAttrList;
301301

302+
/// List of decls that should be printed even if they are implicit and \c SkipImplicit is set to true.
303+
std::vector<const Decl*> TreatAsExplicitDeclList;
304+
302305
/// Whether to print function @convention attribute on function types.
303306
bool PrintFunctionRepresentationAttrs = true;
304307

include/swift/IDE/Utils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ class NameMatcher: public ASTWalker {
268268
std::vector<UnresolvedLoc> LocsToResolve;
269269
std::vector<ResolvedLoc> ResolvedLocs;
270270
ArrayRef<Token> TokensToCheck;
271+
272+
/// The \c Expr argument of a parent \c CustomAttr (if one exists) and
273+
/// the \c SourceLoc of the type name it applies to.
274+
llvm::Optional<std::pair<SourceLoc, Expr *>> CustomAttrArg;
271275
unsigned InactiveConfigRegionNestings = 0;
272276
unsigned SelectorNestings = 0;
273277

@@ -287,6 +291,7 @@ class NameMatcher: public ASTWalker {
287291
bool checkParentForLabels = false);
288292
bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc, LabelRangeType RangeType,
289293
ArrayRef<CharSourceRange> LabelLocs);
294+
bool handleCustomAttrs(Decl *D);
290295

291296
std::pair<bool, Expr*> walkToExprPre(Expr *E) override;
292297
Expr* walkToExprPost(Expr *E) override;

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,8 +1572,11 @@ bool ShouldPrintChecker::shouldPrint(const Decl *D,
15721572
return false;
15731573
}
15741574

1575-
if (Options.SkipImplicit && D->isImplicit())
1576-
return false;
1575+
if (Options.SkipImplicit && D->isImplicit()) {
1576+
const auto &IgnoreList = Options.TreatAsExplicitDeclList;
1577+
if (std::find(IgnoreList.begin(), IgnoreList.end(), D) == IgnoreList.end())
1578+
return false;
1579+
}
15771580

15781581
if (Options.SkipUnavailable &&
15791582
D->getAttrs().isUnavailable(D->getASTContext()))

lib/AST/ASTWalker.cpp

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -122,31 +122,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
122122
return inherited::visit(PL);
123123
}
124124

125-
//===--------------------------------------------------------------------===//
126-
// Attributes
127-
//===--------------------------------------------------------------------===//
128-
bool visitCustomAttributes(Decl *D) {
129-
for (auto *customAttr : D->getAttrs().getAttributes<CustomAttr, true>()) {
130-
CustomAttr *mutableCustomAttr = const_cast<CustomAttr *>(customAttr);
131-
if (doIt(mutableCustomAttr->getTypeLoc()))
132-
return true;
133-
134-
if (auto semanticInit = customAttr->getSemanticInit()) {
135-
if (auto newSemanticInit = doIt(semanticInit))
136-
mutableCustomAttr->setSemanticInit(newSemanticInit);
137-
else
138-
return true;
139-
} else if (auto arg = customAttr->getArg()) {
140-
if (auto newArg = doIt(arg))
141-
mutableCustomAttr->setArg(newArg);
142-
else
143-
return true;
144-
}
145-
}
146-
147-
return false;
148-
}
149-
150125
//===--------------------------------------------------------------------===//
151126
// Decls
152127
//===--------------------------------------------------------------------===//
@@ -179,9 +154,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
179154
// If there is a single variable, walk it's attributes.
180155
bool isPropertyWrapperBackingProperty = false;
181156
if (auto singleVar = PBD->getSingleVar()) {
182-
if (visitCustomAttributes(singleVar))
183-
return true;
184-
185157
isPropertyWrapperBackingProperty =
186158
singleVar->getOriginalWrappedProperty() != nullptr;
187159
}
@@ -1153,9 +1125,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
11531125
if (doIt(P))
11541126
return true;
11551127

1156-
// Visit any custom attributes on the parameter.
1157-
visitCustomAttributes(P);
1158-
11591128
// Don't walk into the type if the decl is implicit, or if the type is
11601129
// implicit.
11611130
if (!P->isImplicit() && !P->isTypeLocImplicit() &&
@@ -1168,7 +1137,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
11681137
P->setDefaultValue(res);
11691138
}
11701139
}
1171-
1140+
11721141
return Walker.walkToParameterListPost(PL);
11731142
}
11741143

@@ -1257,7 +1226,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
12571226

12581227
return P;
12591228
}
1260-
1229+
12611230
bool doIt(const StmtCondition &C) {
12621231
for (auto &elt : C) {
12631232
switch (elt.getKind()) {

lib/IDE/SourceEntityWalker.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class SemaAnnotator : public ASTWalker {
3434
SmallVector<ConstructorRefCallExpr *, 2> CtorRefs;
3535
SmallVector<ExtensionDecl *, 2> ExtDecls;
3636
llvm::SmallDenseMap<OpaqueValueExpr *, Expr *, 4> OpaqueValueMap;
37+
llvm::SmallPtrSet<Expr *, 16> ExprsToSkip;
3738
bool Cancelled = false;
3839
Optional<AccessKind> OpAccess;
3940

@@ -61,6 +62,7 @@ class SemaAnnotator : public ASTWalker {
6162
std::pair<bool, Pattern *> walkToPatternPre(Pattern *P) override;
6263

6364
bool handleImports(ImportDecl *Import);
65+
bool handleCustomAttributes(Decl *D);
6466
bool passModulePathElements(ArrayRef<ImportDecl::AccessPathElement> Path,
6567
const clang::Module *ClangMod);
6668

@@ -95,6 +97,11 @@ bool SemaAnnotator::walkToDeclPre(Decl *D) {
9597
if (shouldIgnore(D, ShouldVisitChildren))
9698
return ShouldVisitChildren;
9799

100+
if (!handleCustomAttributes(D)) {
101+
Cancelled = true;
102+
return false;
103+
}
104+
98105
SourceLoc Loc = D->getLoc();
99106
unsigned NameLen = 0;
100107
bool IsExtension = false;
@@ -252,6 +259,9 @@ std::pair<bool, Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
252259
if (isDone())
253260
return { false, nullptr };
254261

262+
if (ExprsToSkip.count(E) != 0)
263+
return { false, E };
264+
255265
if (!SEWalker.walkToExprPre(E))
256266
return { false, E };
257267

@@ -541,6 +551,41 @@ std::pair<bool, Pattern *> SemaAnnotator::walkToPatternPre(Pattern *P) {
541551
return { false, P };
542552
}
543553

554+
bool SemaAnnotator::handleCustomAttributes(Decl *D) {
555+
// CustomAttrs of non-param VarDecls are handled when this method is called
556+
// on their containing PatternBindingDecls (see below).
557+
if (isa<VarDecl>(D) && !isa<ParamDecl>(D))
558+
return true;
559+
560+
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
561+
if (auto *SingleVar = PBD->getSingleVar()) {
562+
D = SingleVar;
563+
} else {
564+
return true;
565+
}
566+
}
567+
for (auto *customAttr : D->getAttrs().getAttributes<CustomAttr, true>()) {
568+
if (auto *Repr = customAttr->getTypeLoc().getTypeRepr()) {
569+
if (!Repr->walk(*this))
570+
return false;
571+
}
572+
if (auto *SemaInit = customAttr->getSemanticInit()) {
573+
if (!SemaInit->isImplicit()) {
574+
assert(customAttr->getArg());
575+
if (!SemaInit->walk(*this))
576+
return false;
577+
// Don't walk this again via the associated PatternBindingDecl's
578+
// initializer
579+
ExprsToSkip.insert(SemaInit);
580+
}
581+
} else if (auto *Arg = customAttr->getArg()) {
582+
if (!Arg->walk(*this))
583+
return false;
584+
}
585+
}
586+
return true;
587+
}
588+
544589
bool SemaAnnotator::handleImports(ImportDecl *Import) {
545590
auto Mod = Import->getModule();
546591
if (!Mod)

lib/IDE/SwiftSourceDocInfo.cpp

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ bool CursorInfoResolver::tryResolve(ValueDecl *D, TypeDecl *CtorTyRef,
8686
// Handle references to the implicitly generated vars in case statements
8787
// matching multiple patterns
8888
if (VD->isImplicit()) {
89-
if (auto * Parent = VD->getParentVarDecl())
89+
if (auto * Parent = VD->getParentVarDecl()) {
9090
D = Parent;
91+
VD = Parent;
92+
}
9193
}
9294
}
9395
CursorInfo.setValueRef(D, CtorTyRef, ExtTyRef, IsRef, Ty, ContainerType);
@@ -135,7 +137,7 @@ ResolvedCursorInfo CursorInfoResolver::resolve(SourceLoc Loc) {
135137
}
136138

137139
bool CursorInfoResolver::walkToDeclPre(Decl *D, CharSourceRange Range) {
138-
if (!rangeContainsLoc(D->getSourceRange()))
140+
if (!rangeContainsLoc(D->getSourceRangeIncludingAttrs()))
139141
return false;
140142

141143
if (isa<ExtensionDecl>(D))
@@ -354,6 +356,42 @@ static std::vector<CharSourceRange> getEnumParamListInfo(SourceManager &SM,
354356
return LabelRanges;
355357
}
356358

359+
bool NameMatcher::handleCustomAttrs(Decl *D) {
360+
// CustomAttrs of non-param VarDecls are handled when this method is called
361+
// on their containing PatternBindingDecls (see below).
362+
if (isa<VarDecl>(D) && !isa<ParamDecl>(D))
363+
return true;
364+
365+
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
366+
if (auto *SingleVar = PBD->getSingleVar()) {
367+
D = SingleVar;
368+
} else {
369+
return true;
370+
}
371+
}
372+
373+
for (auto *customAttr : D->getAttrs().getAttributes<CustomAttr, true>()) {
374+
if (shouldSkip(customAttr->getRangeWithAt()))
375+
continue;
376+
auto *Arg = customAttr->getArg();
377+
if (auto *Repr = customAttr->getTypeLoc().getTypeRepr()) {
378+
// Note the associated call arguments of the semantic initializer call
379+
// in case we're resolving an explicit initializer call within the
380+
// CustomAttr's type, e.g. on `Wrapper` in `@Wrapper(initialValue: 10)`.
381+
SWIFT_DEFER { CustomAttrArg = None; };
382+
if (Arg && !Arg->isImplicit())
383+
CustomAttrArg = {Repr->getLoc(), Arg};
384+
if (!Repr->walk(*this))
385+
return false;
386+
}
387+
if (Arg && !Arg->isImplicit()) {
388+
if (!Arg->walk(*this))
389+
return false;
390+
}
391+
}
392+
return !isDone();
393+
}
394+
357395
bool NameMatcher::walkToDeclPre(Decl *D) {
358396
// Handle occurrences in any preceding doc comments
359397
RawComment R = D->getRawComment();
@@ -369,9 +407,12 @@ bool NameMatcher::walkToDeclPre(Decl *D) {
369407
if (D->isImplicit())
370408
return !isDone();
371409

372-
if (shouldSkip(D->getSourceRange()))
410+
if (shouldSkip(D->getSourceRangeIncludingAttrs()))
373411
return false;
374412

413+
if (!handleCustomAttrs(D))
414+
return false;
415+
375416
if (auto *ICD = dyn_cast<IfConfigDecl>(D)) {
376417
for (auto Clause : ICD->getClauses()) {
377418
if (!Clause.isActive)
@@ -575,8 +616,16 @@ bool NameMatcher::walkToTypeReprPre(TypeRepr *T) {
575616
if (isDone() || shouldSkip(T->getSourceRange()))
576617
return false;
577618

578-
if (isa<ComponentIdentTypeRepr>(T))
579-
tryResolve(ASTWalker::ParentTy(T), T->getLoc());
619+
if (isa<ComponentIdentTypeRepr>(T)) {
620+
// If we're walking a CustomAttr's type we may have an associated call
621+
// argument to resolve with from its semantic initializer.
622+
if (CustomAttrArg.hasValue() && CustomAttrArg->first == T->getLoc()) {
623+
tryResolve(ASTWalker::ParentTy(T), T->getLoc(), LabelRangeType::CallArg,
624+
getCallArgLabelRanges(getSourceMgr(), CustomAttrArg->second, LabelRangeEndAt::BeforeElemStart));
625+
} else {
626+
tryResolve(ASTWalker::ParentTy(T), T->getLoc());
627+
}
628+
}
580629
return !isDone();
581630
}
582631

@@ -726,13 +775,32 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc,
726775
CharSourceRange Range = Lexer::getCharSourceRangeFromSourceRange(getSourceMgr(),
727776
NameLoc);
728777
UnresolvedLoc &Next = LocsToResolve.back();
729-
if (Range.isValid() && NameLoc == Next.Loc) {
730-
LocsToResolve.pop_back();
731-
ResolvedLocs.push_back({Node, Range, LabelRanges, RangeType,
732-
isActive(), isInSelector()});
733-
return true;
778+
bool WasResolved = false;
779+
if (Range.isValid()) {
780+
if (NameLoc == Next.Loc) {
781+
LocsToResolve.pop_back();
782+
ResolvedLocs.push_back({Node, Range, LabelRanges, RangeType,
783+
isActive(), isInSelector()});
784+
if (isDone())
785+
return true;
786+
WasResolved = true;
787+
}
788+
789+
if (Range.getByteLength() > 1 &&
790+
(Range.str().front() == '_' || Range.str().front() == '$')) {
791+
// Also try after any leading _ or $ for name references of wrapped
792+
// properties, e.g. 'foo' in '_foo' and '$foo' occurrences.
793+
auto NewRange = CharSourceRange(Range.getStart().getAdvancedLoc(1),
794+
Range.getByteLength() - 1);
795+
if (NewRange.getStart() == Next.Loc) {
796+
LocsToResolve.pop_back();
797+
ResolvedLocs.push_back({Node, NewRange, {}, LabelRangeType::None,
798+
isActive(), isInSelector()});
799+
WasResolved = true;
800+
}
801+
}
734802
}
735-
return false;
803+
return WasResolved;
736804
};
737805

738806
void ResolvedRangeInfo::print(llvm::raw_ostream &OS) {

lib/IDE/SyntaxModel.cpp

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,22 +1026,28 @@ bool ModelASTWalker::handleSpecialDeclAttribute(const DeclAttribute *D,
10261026
ArrayRef<Token> Toks) {
10271027
if (!D)
10281028
return false;
1029-
if (isa<AvailableAttr>(D) || isa<CustomAttr>(D)) {
1030-
unsigned I = 0;
1031-
for (; I < TokenNodes.size(); ++ I) {
1032-
auto Node = TokenNodes[I];
1033-
if (SM.isBeforeInBuffer(D->getRange().End, Node.Range.getStart()))
1034-
break;
1035-
if (Node.Range.contains(D->AtLoc)) {
1036-
if (!passNode({SyntaxNodeKind::AttributeBuiltin, Node.Range}))
1037-
break;
1038-
continue;
1029+
if (isa<CustomAttr>(D) || isa<AvailableAttr>(D)) {
1030+
if (!passTokenNodesUntil(D->getRangeWithAt().Start,
1031+
PassNodesBehavior::ExcludeNodeAtLocation))
1032+
return false;
1033+
if (auto *CA = dyn_cast<CustomAttr>(D)) {
1034+
if (auto *Repr = CA->getTypeLoc().getTypeRepr()) {
1035+
if (!Repr->walk(*this))
1036+
return false;
10391037
}
1040-
1041-
if (!passNode(Node))
1042-
break;
1038+
if (auto *Arg = CA->getArg()) {
1039+
if (!Arg->walk(*this))
1040+
return false;
1041+
}
1042+
} else {
1043+
auto Next = TokenNodes.front();
1044+
TokenNodes = TokenNodes.drop_front();
1045+
assert(Next.Range.getStart() == D->getRangeWithAt().Start);
1046+
if (!passNode({SyntaxNodeKind::AttributeBuiltin, Next.Range}))
1047+
return false;
10431048
}
1044-
TokenNodes = TokenNodes.slice(I);
1049+
if (!passTokenNodesUntil(D->getRange().End, PassNodesBehavior::IncludeNodeAtLocation))
1050+
return false;
10451051
return true;
10461052
}
10471053
if (isa<RethrowsAttr>(D))
@@ -1078,6 +1084,13 @@ bool ModelASTWalker::handleAttrRanges(ArrayRef<DeclAttributeAndRange> DeclRanges
10781084
[&](DeclAttributeAndRange LHS, DeclAttributeAndRange RHS) {
10791085
return SM.isBeforeInBuffer(LHS.second.Start, RHS.second.End);
10801086
});
1087+
// Handle duplicate synthesized attributes due to * in @available
1088+
auto NewEnd = std::unique(SortedRanges.begin(), SortedRanges.end(),
1089+
[&](DeclAttributeAndRange LHS, DeclAttributeAndRange RHS) {
1090+
return LHS.second == RHS.second;
1091+
});
1092+
if (NewEnd != SortedRanges.end())
1093+
SortedRanges.erase(NewEnd, SortedRanges.end());
10811094
DeclRanges = SortedRanges;
10821095

10831096
SourceLoc BeginLoc = DeclRanges.front().second.Start;

0 commit comments

Comments
 (0)