Skip to content

Commit 79e31a8

Browse files
committed
Re-implement ASTScope's child-insertion assertions
ASTScope assertions that a new child node inserted into its parent list is after all other child nodes in the source, which included some bespoke code for dealing with macro expansions. Replace this bespoke code with uses of the newer SourceManager operations that check ordering of source locations in a manner that respects macro expansions.
1 parent 37ed49e commit 79e31a8

File tree

5 files changed

+61
-43
lines changed

5 files changed

+61
-43
lines changed

include/swift/AST/ASTScope.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class ASTScopeImpl : public ASTAllocated<ASTScopeImpl> {
155155
/// Child scopes, sorted by source range.
156156
Children storedChildren;
157157

158-
mutable llvm::Optional<CharSourceRange> cachedCharSourceRange;
158+
mutable llvm::Optional<SourceRange> cachedCharSourceRange;
159159

160160
#pragma mark - constructor / destructor
161161
public:
@@ -194,8 +194,17 @@ class ASTScopeImpl : public ASTAllocated<ASTScopeImpl> {
194194
#pragma mark - source ranges
195195

196196
public:
197-
CharSourceRange getCharSourceRangeOfScope(SourceManager &SM,
198-
bool omitAssertions = false) const;
197+
/// Retrieve the source range of the given scope, where the end location
198+
/// is adjusted to refer to the end of the token.
199+
///
200+
/// Since the adjustment to the end of the token requires lexing, this
201+
/// routine also caches the result.
202+
///
203+
/// Note that the start and end locations might be in different source
204+
/// buffers, so we represent the result as SourceRange rather than
205+
/// CharSourceRange.
206+
SourceRange getCharSourceRangeOfScope(SourceManager &SM,
207+
bool omitAssertions = false) const;
199208
bool isCharSourceRangeCached() const;
200209

201210
/// Returns source range of this node alone, without factoring in any

include/swift/Basic/SourceManager.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,20 @@ class SourceManager {
255255
/// part of the same source file, for example due to macro expansion.
256256
bool containsTokenLoc(SourceRange range, SourceLoc loc) const;
257257

258+
/// Returns true if \c range contains the location \c loc.
259+
///
260+
/// This function accounts for the possibility that the source locations
261+
/// provided might come from different source buffers that are conceptually
262+
/// part of the same source file, for example due to macro expansion.
263+
bool containsLoc(SourceRange range, SourceLoc loc) const;
264+
265+
/// Returns true if \c enclosing contains the whole range \c inner.
266+
///
267+
/// This function accounts for the possibility that the source locations
268+
/// provided might come from different source buffers that are conceptually
269+
/// part of the same source file, for example due to macro expansion.
270+
bool encloses(SourceRange enclosing, SourceRange inner) const;
271+
258272
/// Returns true if range \c R contains the location \c Loc, where all
259273
/// locations are known to be in the same source buffer.
260274
///

lib/AST/ASTScopeLookup.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,16 @@ ASTScopeImpl::findChildContaining(ModuleDecl *parentModule,
120120
auto *const *child = llvm::lower_bound(
121121
getChildren(), loc,
122122
[&](const ASTScopeImpl *scope, SourceLoc loc) {
123-
auto rangeOfScope = scope->getSourceRangeOfThisASTNode();
124-
auto endOfScope =
125-
Lexer::getLocForEndOfToken(sourceMgr, rangeOfScope.End);
126-
123+
auto rangeOfScope = scope->getCharSourceRangeOfScope(sourceMgr);
127124
loc = translateLocForReplacedRange(sourceMgr, rangeOfScope.Start, loc);
128-
return sourceMgr.isAtOrBefore(endOfScope, loc);
125+
return sourceMgr.isAtOrBefore(rangeOfScope.End, loc);
129126
});
130127

131128
if (child != getChildren().end()) {
132-
auto rangeOfScope = (*child)->getSourceRangeOfThisASTNode();
133-
auto endOfScope = Lexer::getLocForEndOfToken(sourceMgr, rangeOfScope.End);
129+
auto rangeOfScope = (*child)->getCharSourceRangeOfScope(sourceMgr);
134130
loc = translateLocForReplacedRange(sourceMgr, rangeOfScope.Start, loc);
135131
if (sourceMgr.isAtOrBefore(rangeOfScope.Start, loc) &&
136-
sourceMgr.isBefore(loc, endOfScope))
132+
sourceMgr.isBefore(loc, rangeOfScope.End))
137133
return *child;
138134
}
139135

lib/AST/ASTScopeSourceRange.cpp

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ using namespace ast_scope;
3838

3939
static SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *);
4040

41+
/// Retrieve the character-based source range for the given source range.
42+
static SourceRange getCharSourceRange(
43+
SourceManager &sourceMgr, SourceRange range
44+
){
45+
range.End = Lexer::getLocForEndOfToken(sourceMgr, range.End);
46+
return range;
47+
}
48+
4149
void ASTScopeImpl::checkSourceRangeBeforeAddingChild(ASTScopeImpl *child,
4250
const ASTContext &ctx) const {
4351
// Ignore debugger bindings - they're a special mix of user code and implicit
@@ -51,35 +59,18 @@ void ASTScopeImpl::checkSourceRangeBeforeAddingChild(ASTScopeImpl *child,
5159

5260
auto range = getCharSourceRangeOfScope(sourceMgr);
5361

54-
std::function<bool(CharSourceRange)> containedInParent;
55-
containedInParent = [&](CharSourceRange childCharRange) {
62+
std::function<bool(SourceRange)> containedInParent;
63+
containedInParent = [&](SourceRange childCharRange) {
5664
// HACK: For code completion. Handle replaced range.
5765
for (const auto &pair : sourceMgr.getReplacedRanges()) {
58-
auto originalRange =
59-
Lexer::getCharSourceRangeFromSourceRange(sourceMgr, pair.first);
60-
auto newRange =
61-
Lexer::getCharSourceRangeFromSourceRange(sourceMgr, pair.second);
62-
if (range.contains(originalRange) &&
63-
newRange.contains(childCharRange))
66+
auto originalRange = getCharSourceRange(sourceMgr, pair.first);
67+
auto newRange = getCharSourceRange(sourceMgr, pair.second);
68+
if (sourceMgr.encloses(range, originalRange) &&
69+
sourceMgr.encloses(newRange, childCharRange))
6470
return true;
6571
}
6672

67-
if (range.contains(childCharRange))
68-
return true;
69-
70-
// If this is from a macro expansion, look at the where the expansion
71-
// occurred.
72-
auto childBufferID =
73-
sourceMgr.findBufferContainingLoc(childCharRange.getStart());
74-
auto generatedInfo = sourceMgr.getGeneratedSourceInfo(childBufferID);
75-
if (!generatedInfo)
76-
return false;
77-
78-
CharSourceRange expansionRange = generatedInfo->originalSourceRange;
79-
if (expansionRange.isInvalid())
80-
return false;
81-
82-
return containedInParent(expansionRange);
73+
return sourceMgr.encloses(range, childCharRange);
8374
};
8475

8576
auto childCharRange = child->getCharSourceRangeOfScope(sourceMgr);
@@ -95,11 +86,9 @@ void ASTScopeImpl::checkSourceRangeBeforeAddingChild(ASTScopeImpl *child,
9586
if (!storedChildren.empty()) {
9687
auto previousChild = storedChildren.back();
9788
auto endOfPreviousChild = previousChild->getCharSourceRangeOfScope(
98-
sourceMgr).getEnd();
89+
sourceMgr).End;
9990

100-
if (childCharRange.getStart() != endOfPreviousChild &&
101-
!sourceMgr.isBeforeInBuffer(endOfPreviousChild,
102-
childCharRange.getStart())) {
91+
if (!sourceMgr.isAtOrBefore(endOfPreviousChild, childCharRange.Start)) {
10392
auto &out = verificationError() << "child overlaps previous child:\n";
10493
child->print(out);
10594
out << "\n***Previous child\n";
@@ -384,18 +373,19 @@ SourceRange GuardStmtBodyScope::getSourceRangeOfThisASTNode(
384373

385374
#pragma mark source range caching
386375

387-
CharSourceRange
376+
SourceRange
388377
ASTScopeImpl::getCharSourceRangeOfScope(SourceManager &SM,
389378
bool omitAssertions) const {
390379
if (!isCharSourceRangeCached()) {
391380
auto range = getSourceRangeOfThisASTNode(omitAssertions);
392381
ASTScopeAssert(range.isValid(), "scope has invalid source range");
393-
ASTScopeAssert(SM.isBeforeInBuffer(range.Start, range.End) ||
382+
ASTScopeAssert(SM.isBefore(range.Start, range.End) ||
394383
range.Start == range.End,
395384
"scope source range ends before start");
396385

397-
cachedCharSourceRange =
398-
Lexer::getCharSourceRangeFromSourceRange(SM, range);
386+
range.End = Lexer::getLocForEndOfToken(SM, range.End);
387+
388+
cachedCharSourceRange = range;
399389
}
400390

401391
return *cachedCharSourceRange;

lib/Basic/SourceLoc.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,3 +817,12 @@ bool SourceManager::isAtOrBefore(SourceLoc first, SourceLoc second) const {
817817
bool SourceManager::containsTokenLoc(SourceRange range, SourceLoc loc) const {
818818
return isAtOrBefore(range.Start, loc) && isAtOrBefore(loc, range.End);
819819
}
820+
821+
bool SourceManager::containsLoc(SourceRange range, SourceLoc loc) const {
822+
return isAtOrBefore(range.Start, loc) && isBefore(loc, range.End);
823+
}
824+
825+
bool SourceManager::encloses(SourceRange enclosing, SourceRange inner) const {
826+
return containsLoc(enclosing, inner.Start) &&
827+
isAtOrBefore(inner.End, enclosing.End);
828+
}

0 commit comments

Comments
 (0)