Skip to content

Commit 4f1ab9d

Browse files
committed
ASTScope: Directly calculate end location of GuardStmtScope and PatternEntryDeclScope
Today, the reported source range of a GuardStmtScope is just that of the statement itself, ending after the 'else' block. Similarly, a PatternEntryDeclScope ends immediately after the initializer expression. Since these scopes introduce names until the end of the parent BraceStmt (meaning they change the insertion point), we were relying on the addition of child scopes to extend the source range. While we still need the hack for extending source ranges to deal with string interpolation, at least in the other cases we can get rid of it. Note that this fixes a bug where a GuardStmtScope would end before an inactive '#if' block if the inactive '#if' block was the last element of a BraceStmt.
1 parent 8b2cf55 commit 4f1ab9d

File tree

4 files changed

+114
-44
lines changed

4 files changed

+114
-44
lines changed

include/swift/AST/ASTScope.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,7 @@ class AbstractPatternEntryScope : public ASTScopeImpl {
10401040

10411041
class PatternEntryDeclScope final : public AbstractPatternEntryScope {
10421042
const bool isLocalBinding;
1043+
Optional<SourceLoc> endLoc;
10431044

10441045
public:
10451046
PatternEntryDeclScope(PatternBindingDecl *pbDecl, unsigned entryIndex,
@@ -1400,7 +1401,8 @@ class WhileStmtScope final : public LabeledConditionalStmtScope {
14001401
class GuardStmtScope final : public LabeledConditionalStmtScope {
14011402
public:
14021403
GuardStmt *const stmt;
1403-
GuardStmtScope(GuardStmt *e) : stmt(e) {}
1404+
SourceLoc endLoc;
1405+
GuardStmtScope(GuardStmt *e, SourceLoc endLoc) : stmt(e), endLoc(endLoc) {}
14041406
virtual ~GuardStmtScope() {}
14051407

14061408
protected:
@@ -1413,6 +1415,8 @@ class GuardStmtScope final : public LabeledConditionalStmtScope {
14131415
public:
14141416
std::string getClassName() const override;
14151417
LabeledConditionalStmt *getLabeledConditionalStmt() const override;
1418+
SourceRange
1419+
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
14161420
};
14171421

14181422
/// A scope after a guard statement that follows lookups into the conditions
@@ -1427,9 +1431,11 @@ class LookupParentDiversionScope final : public ASTScopeImpl {
14271431
public:
14281432
ASTScopeImpl *const lookupParent;
14291433
const SourceLoc startLoc;
1434+
const SourceLoc endLoc;
14301435

1431-
LookupParentDiversionScope(ASTScopeImpl *lookupParent, SourceLoc startLoc)
1432-
: lookupParent(lookupParent), startLoc(startLoc) {}
1436+
LookupParentDiversionScope(ASTScopeImpl *lookupParent,
1437+
SourceLoc startLoc, SourceLoc endLoc)
1438+
: lookupParent(lookupParent), startLoc(startLoc), endLoc(endLoc) {}
14331439

14341440
SourceRange
14351441
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;

lib/AST/ASTScopeCreation.cpp

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,17 @@ class ScopeCreator final {
213213

214214
/// Given an array of ASTNodes or Decl pointers, add them
215215
/// Return the resultant insertionPoint
216+
///
217+
/// \param endLoc The end location for any "scopes until the end" that
218+
/// we introduce here, such as PatternEntryDeclScope and GuardStmtScope
216219
ASTScopeImpl *
217220
addSiblingsToScopeTree(ASTScopeImpl *const insertionPoint,
218-
ASTScopeImpl *const organicInsertionPoint,
219-
ArrayRef<ASTNode> nodesOrDeclsToAdd) {
221+
ArrayRef<ASTNode> nodesOrDeclsToAdd,
222+
Optional<SourceLoc> endLoc) {
220223
auto *ip = insertionPoint;
221224
for (auto nd : nodesOrDeclsToAdd) {
222225
auto *const newIP =
223-
addToScopeTreeAndReturnInsertionPoint(nd, ip).getPtrOr(ip);
226+
addToScopeTreeAndReturnInsertionPoint(nd, ip, endLoc).getPtrOr(ip);
224227
ip = newIP;
225228
}
226229
return ip;
@@ -229,12 +232,16 @@ class ScopeCreator final {
229232
public:
230233
/// For each of searching, call this unless the insertion point is needed
231234
void addToScopeTree(ASTNode n, ASTScopeImpl *parent) {
232-
(void)addToScopeTreeAndReturnInsertionPoint(n, parent);
235+
(void)addToScopeTreeAndReturnInsertionPoint(n, parent, None);
233236
}
234237
/// Return new insertion point if the scope was not a duplicate
235238
/// For ease of searching, don't call unless insertion point is needed
239+
///
240+
/// \param endLoc The end location for any "scopes until the end" that
241+
/// we introduce here, such as PatternEntryDeclScope and GuardStmtScope
236242
NullablePtr<ASTScopeImpl>
237-
addToScopeTreeAndReturnInsertionPoint(ASTNode, ASTScopeImpl *parent);
243+
addToScopeTreeAndReturnInsertionPoint(ASTNode, ASTScopeImpl *parent,
244+
Optional<SourceLoc> endLoc);
238245

239246
bool isWorthTryingToCreateScopeFor(ASTNode n) const {
240247
if (!n)
@@ -419,6 +426,18 @@ class ScopeCreator final {
419426
void addChildrenForKnownAttributes(ValueDecl *decl,
420427
ASTScopeImpl *parent);
421428

429+
/// Add PatternEntryDeclScopes for each pattern binding entry.
430+
///
431+
/// Returns the new insertion point.
432+
///
433+
/// \param endLoc Must be valid iff the pattern binding is in a local
434+
/// scope, in which case this is the last source location where the
435+
/// pattern bindings are going to be visible.
436+
NullablePtr<ASTScopeImpl>
437+
addPatternBindingToScopeTree(PatternBindingDecl *patternBinding,
438+
ASTScopeImpl *parent,
439+
Optional<SourceLoc> endLoc);
440+
422441
/// Remove VarDecls because we'll find them when we expand the
423442
/// PatternBindingDecls. Remove EnunCases
424443
/// because they overlap EnumElements and AST includes the elements in the
@@ -541,7 +560,10 @@ class NodeAdder
541560
: public ASTVisitor<NodeAdder, NullablePtr<ASTScopeImpl>,
542561
NullablePtr<ASTScopeImpl>, NullablePtr<ASTScopeImpl>,
543562
void, void, void, ASTScopeImpl *, ScopeCreator &> {
563+
Optional<SourceLoc> endLoc;
564+
544565
public:
566+
explicit NodeAdder(Optional<SourceLoc> endLoc) : endLoc(endLoc) {}
545567

546568
#pragma mark ASTNodes that do not create scopes
547569

@@ -633,7 +655,9 @@ class NodeAdder
633655
// the deferred nodes.
634656
NullablePtr<ASTScopeImpl> visitGuardStmt(GuardStmt *e, ASTScopeImpl *p,
635657
ScopeCreator &scopeCreator) {
636-
return scopeCreator.ifUniqueConstructExpandAndInsert<GuardStmtScope>(p, e);
658+
ASTScopeAssert(endLoc.hasValue(), "GuardStmt outside of a BraceStmt?");
659+
return scopeCreator.ifUniqueConstructExpandAndInsert<GuardStmtScope>(
660+
p, e, *endLoc);
637661
}
638662
NullablePtr<ASTScopeImpl> visitTopLevelCodeDecl(TopLevelCodeDecl *d,
639663
ASTScopeImpl *p,
@@ -694,28 +718,8 @@ class NodeAdder
694718
visitPatternBindingDecl(PatternBindingDecl *patternBinding,
695719
ASTScopeImpl *parentScope,
696720
ScopeCreator &scopeCreator) {
697-
if (auto *var = patternBinding->getSingleVar())
698-
scopeCreator.addChildrenForKnownAttributes(var, parentScope);
699-
700-
auto *insertionPoint = parentScope;
701-
for (auto i : range(patternBinding->getNumPatternEntries())) {
702-
bool isLocalBinding = false;
703-
if (auto *varDecl = patternBinding->getAnchoringVarDecl(i)) {
704-
isLocalBinding = varDecl->getDeclContext()->isLocalContext();
705-
}
706-
707-
insertionPoint =
708-
scopeCreator
709-
.ifUniqueConstructExpandAndInsert<PatternEntryDeclScope>(
710-
insertionPoint, patternBinding, i, isLocalBinding)
711-
.getPtrOr(insertionPoint);
712-
713-
ASTScopeAssert(isLocalBinding || insertionPoint == parentScope,
714-
"Bindings at the top-level or members of types should "
715-
"not change the insertion point");
716-
}
717-
718-
return insertionPoint;
721+
return scopeCreator.addPatternBindingToScopeTree(
722+
patternBinding, parentScope, endLoc);
719723
}
720724

721725
NullablePtr<ASTScopeImpl> visitEnumElementDecl(EnumElementDecl *eed,
@@ -769,15 +773,18 @@ class NodeAdder
769773
// NodeAdder
770774
NullablePtr<ASTScopeImpl>
771775
ScopeCreator::addToScopeTreeAndReturnInsertionPoint(ASTNode n,
772-
ASTScopeImpl *parent) {
776+
ASTScopeImpl *parent,
777+
Optional<SourceLoc> endLoc) {
773778
if (!isWorthTryingToCreateScopeFor(n))
774779
return parent;
780+
781+
NodeAdder adder(endLoc);
775782
if (auto *p = n.dyn_cast<Decl *>())
776-
return NodeAdder().visit(p, parent, *this);
783+
return adder.visit(p, parent, *this);
777784
if (auto *p = n.dyn_cast<Expr *>())
778-
return NodeAdder().visit(p, parent, *this);
785+
return adder.visit(p, parent, *this);
779786
auto *p = n.get<Stmt *>();
780-
return NodeAdder().visit(p, parent, *this);
787+
return adder.visit(p, parent, *this);
781788
}
782789

783790
void ScopeCreator::addChildrenForAllLocalizableAccessorsInSourceOrder(
@@ -827,6 +834,41 @@ void ScopeCreator::addChildrenForKnownAttributes(ValueDecl *decl,
827834
}
828835
}
829836

837+
NullablePtr<ASTScopeImpl>
838+
ScopeCreator::addPatternBindingToScopeTree(PatternBindingDecl *patternBinding,
839+
ASTScopeImpl *parentScope,
840+
Optional<SourceLoc> endLoc) {
841+
if (auto *var = patternBinding->getSingleVar())
842+
addChildrenForKnownAttributes(var, parentScope);
843+
844+
auto *insertionPoint = parentScope;
845+
for (auto i : range(patternBinding->getNumPatternEntries())) {
846+
bool isLocalBinding = false;
847+
if (auto *varDecl = patternBinding->getAnchoringVarDecl(i)) {
848+
isLocalBinding = varDecl->getDeclContext()->isLocalContext();
849+
}
850+
851+
Optional<SourceLoc> endLocForBinding = None;
852+
if (isLocalBinding) {
853+
endLocForBinding = endLoc;
854+
ASTScopeAssert(endLoc.hasValue() && endLoc->isValid(),
855+
"PatternBindingDecl in local context outside of BraceStmt?");
856+
}
857+
858+
insertionPoint =
859+
ifUniqueConstructExpandAndInsert<PatternEntryDeclScope>(
860+
insertionPoint, patternBinding, i,
861+
isLocalBinding, endLocForBinding)
862+
.getPtrOr(insertionPoint);
863+
864+
ASTScopeAssert(isLocalBinding || insertionPoint == parentScope,
865+
"Bindings at the top-level or members of types should "
866+
"not change the insertion point");
867+
}
868+
869+
return insertionPoint;
870+
}
871+
830872
#pragma mark creation helpers
831873

832874
void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) {
@@ -946,9 +988,10 @@ ASTSourceFileScope::expandAScopeThatCreatesANewInsertionPoint(
946988
// Assume that decls are only added at the end, in source order
947989
std::vector<ASTNode> newNodes(decls.begin(), decls.end());
948990
insertionPoint =
949-
scopeCreator.addSiblingsToScopeTree(insertionPoint, this,
991+
scopeCreator.addSiblingsToScopeTree(insertionPoint,
950992
scopeCreator.sortBySourceRange(
951-
scopeCreator.cull(newNodes)));
993+
scopeCreator.cull(newNodes)),
994+
None);
952995
// Too slow to perform all the time:
953996
// ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(),
954997
// "ASTScope tree missed some DeclContexts or made some up");
@@ -1048,7 +1091,7 @@ GuardStmtScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &
10481091
auto *const lookupParentDiversionScope =
10491092
scopeCreator
10501093
.constructExpandAndInsertUncheckable<LookupParentDiversionScope>(
1051-
this, conditionLookupParent, stmt->getEndLoc());
1094+
this, conditionLookupParent, stmt->getEndLoc(), endLoc);
10521095
return {lookupParentDiversionScope,
10531096
"Succeeding code must be in scope of guard variables"};
10541097
}
@@ -1066,10 +1109,11 @@ BraceStmtScope::expandAScopeThatCreatesANewInsertionPoint(
10661109
// TODO: remove the sort after fixing parser to create brace statement
10671110
// elements in source order
10681111
auto *insertionPoint =
1069-
scopeCreator.addSiblingsToScopeTree(this, this,
1112+
scopeCreator.addSiblingsToScopeTree(this,
10701113
scopeCreator.sortBySourceRange(
10711114
scopeCreator.cull(
1072-
stmt->getElements())));
1115+
stmt->getElements())),
1116+
stmt->getEndLoc());
10731117
if (auto *s = scopeCreator.getASTContext().Stats)
10741118
++s->getFrontendCounters().NumBraceStmtASTScopeExpansions;
10751119
return {
@@ -1083,7 +1127,7 @@ TopLevelCodeScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &
10831127

10841128
if (auto *body =
10851129
scopeCreator
1086-
.addToScopeTreeAndReturnInsertionPoint(decl->getBody(), this)
1130+
.addToScopeTreeAndReturnInsertionPoint(decl->getBody(), this, None)
10871131
.getPtrOrNull())
10881132
return {body, "So next top level code scope and put its decls in its body "
10891133
"under a guard statement scope (etc) from the last top level "
@@ -1414,7 +1458,7 @@ void GenericTypeOrExtensionScope::expandBody(ScopeCreator &) {}
14141458
void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) {
14151459
auto nodes = asNodeVector(getIterableDeclContext().get()->getMembers());
14161460
nodes = scopeCreator.sortBySourceRange(scopeCreator.cull(nodes));
1417-
scopeCreator.addSiblingsToScopeTree(this, this, nodes);
1461+
scopeCreator.addSiblingsToScopeTree(this, nodes, None);
14181462
if (auto *s = scopeCreator.getASTContext().Stats)
14191463
++s->getFrontendCounters().NumIterableTypeBodyASTScopeExpansions;
14201464
}

lib/AST/ASTScopeSourceRange.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,13 @@ SourceRange DefaultArgumentInitializerScope::getSourceRangeOfThisASTNode(
248248

249249
SourceRange PatternEntryDeclScope::getSourceRangeOfThisASTNode(
250250
const bool omitAssertions) const {
251-
return getPatternEntry().getSourceRange();
251+
SourceRange range = getPatternEntry().getSourceRange();
252+
if (endLoc.hasValue()) {
253+
ASTScopeAssert(endLoc->isValid(),
254+
"BraceStmt ends before pattern binding entry?");
255+
range.End = *endLoc;
256+
}
257+
return range;
252258
}
253259

254260
SourceRange PatternEntryInitializerScope::getSourceRangeOfThisASTNode(
@@ -445,9 +451,14 @@ SourceRange AttachedPropertyWrapperScope::getSourceRangeOfThisASTNode(
445451
return sourceRangeWhenCreated;
446452
}
447453

454+
SourceRange GuardStmtScope::getSourceRangeOfThisASTNode(
455+
const bool omitAssertions) const {
456+
return SourceRange(getStmt()->getStartLoc(), endLoc);
457+
}
458+
448459
SourceRange LookupParentDiversionScope::getSourceRangeOfThisASTNode(
449460
const bool omitAssertions) const {
450-
return SourceRange(startLoc);
461+
return SourceRange(startLoc, endLoc);
451462
}
452463

453464
#pragma mark source range caching

test/decl/var/usage.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ func testBuildConfigs() {
242242
#endif
243243
}
244244

245+
// same as above, but with a guard statement
246+
func testGuardWithPoundIf(x: Int?) {
247+
guard let x = x else { return }
248+
249+
#if false
250+
_ = x
251+
#endif
252+
}
253+
245254
// <rdar://problem/21091625> Bogus 'never mutated' warning when protocol variable is mutated only by mutating method
246255
protocol Fooable {
247256
mutating func mutFoo()

0 commit comments

Comments
 (0)