@@ -47,7 +47,26 @@ void ASTScopeImpl::unqualifiedLookup(
47
47
48
48
const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup (
49
49
SourceFile *sourceFile, const SourceLoc loc) {
50
- auto *const fileScope = sourceFile->getScope ().impl ;
50
+ auto *fileScope = sourceFile->getScope ().impl ;
51
+
52
+ // Workaround for bad locations; just return the file scope.
53
+ if (loc.isInvalid ())
54
+ return fileScope;
55
+
56
+ // Some callers get the actual source file wrong. Look for the actual
57
+ // source file containing this location.
58
+ auto actualSF =
59
+ sourceFile->getParentModule ()->getSourceFileContainingLocation (loc);
60
+
61
+ // If there is no source file containing this location, just return the
62
+ // scope we have.
63
+ if (!actualSF)
64
+ return fileScope;
65
+
66
+ // Grab the new file scope.
67
+ if (actualSF != sourceFile)
68
+ fileScope = actualSF->getScope ().impl ;
69
+
51
70
const auto *innermost = fileScope->findInnermostEnclosingScope (
52
71
sourceFile->getParentModule (), loc, nullptr );
53
72
ASTScopeAssert (innermost->getWasExpanded (),
@@ -79,104 +98,101 @@ ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl(
79
98
// / If the \p loc is in a new buffer but \p range is not, consider the location
80
99
// / is at the start of replaced range. Otherwise, returns \p loc as is.
81
100
static SourceLoc translateLocForReplacedRange (SourceManager &sourceMgr,
82
- CharSourceRange range ,
101
+ SourceLoc rangeStart ,
83
102
SourceLoc loc) {
84
103
for (const auto &pair : sourceMgr.getReplacedRanges ()) {
85
104
if (sourceMgr.rangeContainsTokenLoc (pair.second , loc) &&
86
- !sourceMgr.rangeContainsTokenLoc (pair.second , range. getStart () )) {
105
+ !sourceMgr.rangeContainsTokenLoc (pair.second , rangeStart )) {
87
106
return pair.first .Start ;
88
107
}
89
108
}
90
109
return loc;
91
110
}
92
111
112
+ // / Populate the ancestors list for this buffer, with the root source buffer
113
+ // / at the beginning and the given source buffer at the end.
114
+ static void populateAncestors (
115
+ SourceManager &sourceMgr, unsigned bufferID,
116
+ SmallVectorImpl<unsigned > &ancestors) {
117
+ if (auto info = sourceMgr.getGeneratedSourceInfo (bufferID)) {
118
+ auto ancestorLoc = info->originalSourceRange .getStart ();
119
+ if (ancestorLoc.isValid ()) {
120
+ auto ancestorBufferID = sourceMgr.findBufferContainingLoc (ancestorLoc);
121
+ populateAncestors (sourceMgr, ancestorBufferID, ancestors);
122
+ }
123
+ }
124
+
125
+ ancestors.push_back (bufferID);
126
+ }
127
+
128
+ // / Determine whether the first source location precedes the second, accounting
129
+ // / for macro expansions.
130
+ static bool isBeforeInSource (
131
+ SourceManager &sourceMgr, SourceLoc firstLoc, SourceLoc secondLoc,
132
+ bool allowEqual) {
133
+ // If the two locations are in the same source buffer, compare their pointers.
134
+ unsigned firstBufferID = sourceMgr.findBufferContainingLoc (firstLoc);
135
+ unsigned secondBufferID = sourceMgr.findBufferContainingLoc (secondLoc);
136
+ if (firstBufferID == secondBufferID) {
137
+ return sourceMgr.isBeforeInBuffer (firstLoc, secondLoc) ||
138
+ (allowEqual && firstLoc == secondLoc);
139
+ }
140
+
141
+ // If the two locations are in different source buffers, we need to compute
142
+ // the least common ancestor.
143
+ SmallVector<unsigned , 4 > firstAncestors;
144
+ populateAncestors (sourceMgr, firstBufferID, firstAncestors);
145
+ SmallVector<unsigned , 4 > secondAncestors;
146
+ populateAncestors (sourceMgr, secondBufferID, secondAncestors);
147
+
148
+ // Find the first mismatch between the two ancestor lists; this is the
149
+ // point of divergence.
150
+ auto [firstMismatch, secondMismatch] = std::mismatch (
151
+ firstAncestors.begin (), firstAncestors.end (),
152
+ secondAncestors.begin (), secondAncestors.end ());
153
+ assert (firstMismatch != firstAncestors.begin () &&
154
+ secondMismatch != secondAncestors.begin () &&
155
+ " Ancestors don't have the same root source file" );
156
+
157
+ SourceLoc firstLocInLCA = firstMismatch == firstAncestors.end ()
158
+ ? firstLoc
159
+ : sourceMgr.getGeneratedSourceInfo (*firstMismatch)
160
+ ->originalSourceRange .getStart ();
161
+ SourceLoc secondLocInLCA = secondMismatch == secondAncestors.end ()
162
+ ? secondLoc
163
+ : sourceMgr.getGeneratedSourceInfo (*secondMismatch)
164
+ ->originalSourceRange .getStart ();
165
+ return sourceMgr.isBeforeInBuffer (firstLocInLCA, secondLocInLCA) ||
166
+ (allowEqual && firstLocInLCA == secondLocInLCA);
167
+ }
168
+
93
169
NullablePtr<ASTScopeImpl>
94
170
ASTScopeImpl::findChildContaining (ModuleDecl *parentModule,
95
171
SourceLoc loc,
96
172
SourceManager &sourceMgr) const {
97
- auto *locSourceFile = parentModule->getSourceFileContainingLocation (loc);
173
+ if (loc.isInvalid ())
174
+ return nullptr ;
98
175
99
176
// Use binary search to find the child that contains this location.
100
177
auto *const *child = llvm::lower_bound (
101
178
getChildren (), loc,
102
179
[&](const ASTScopeImpl *scope, SourceLoc loc) {
103
- auto rangeOfScope = scope->getCharSourceRangeOfScope (sourceMgr);
104
- ASTScopeAssert (!sourceMgr.isBeforeInBuffer (rangeOfScope.getEnd (),
105
- rangeOfScope.getStart ()),
106
- " Source range is backwards" );
107
-
108
- // If the scope source range and the loc are in two different source
109
- // files, one or both of them are in a macro expansion buffer.
110
-
111
- // Note that `scope->getSourceFile()` returns the root of the source tree,
112
- // not the source file containing the location of the ASTScope.
113
- auto scopeStart = scope->getSourceRangeOfThisASTNode ().Start ;
114
- auto *scopeSourceFile = parentModule->getSourceFileContainingLocation (scopeStart);
115
-
116
- if (scopeSourceFile != locSourceFile) {
117
- // To compare a source location that is possibly inside a macro expansion
118
- // with a source range that is also possibly in a macro expansion (not
119
- // necessarily the same one as before) we need to find the LCA in the
120
- // source file tree of macro expansions, and compare the original source
121
- // ranges within that common ancestor. We can't walk all the way up to the
122
- // source file containing the parent scope we're searching the children of,
123
- // because two independent (possibly nested) macro expansions can have the
124
- // same original source range in that file; freestanding and peer macros
125
- // mean that we can have arbitrarily nested macro expansions that all add
126
- // declarations to the same scope, that all originate from a single macro
127
- // invocation in the original source file.
128
-
129
- // A map from enclosing source files to original source ranges of the macro
130
- // expansions within that file, recording the chain of macro expansions for
131
- // the given scope.
132
- llvm::SmallDenseMap<const SourceFile *, CharSourceRange>
133
- scopeExpansions;
134
-
135
- // Walk up the chain of macro expansion buffers for the scope, recording the
136
- // original source range of the macro expansion along the way using generated
137
- // source info.
138
- auto *scopeExpansion = scopeSourceFile;
139
- scopeExpansions[scopeExpansion] =
140
- Lexer::getCharSourceRangeFromSourceRange (
141
- sourceMgr, scope->getSourceRangeOfThisASTNode ());
142
- while (auto *ancestor = scopeExpansion->getEnclosingSourceFile ()) {
143
- auto generatedInfo =
144
- sourceMgr.getGeneratedSourceInfo (*scopeExpansion->getBufferID ());
145
- scopeExpansions[ancestor] = generatedInfo->originalSourceRange ;
146
- scopeExpansion = ancestor;
147
- }
148
-
149
- // Walk up the chain of macro expansion buffers for the source loc we're
150
- // searching for to find the LCA using `scopeExpansions`.
151
- auto *potentialLCA = locSourceFile;
152
- auto expansionLoc = loc;
153
- while (potentialLCA) {
154
- auto scopeExpansion = scopeExpansions.find (potentialLCA);
155
- if (scopeExpansion != scopeExpansions.end ()) {
156
- // Take the original expansion range within the LCA of the loc and
157
- // the scope to compare.
158
- rangeOfScope = scopeExpansion->second ;
159
- loc = expansionLoc;
160
- break ;
161
- }
162
-
163
- auto generatedInfo =
164
- sourceMgr.getGeneratedSourceInfo (*potentialLCA->getBufferID ());
165
- if (generatedInfo)
166
- expansionLoc = generatedInfo->originalSourceRange .getStart ();
167
- potentialLCA = potentialLCA->getEnclosingSourceFile ();
168
- }
169
- }
170
-
171
- loc = translateLocForReplacedRange (sourceMgr, rangeOfScope, loc);
172
- return (rangeOfScope.getEnd () == loc ||
173
- sourceMgr.isBeforeInBuffer (rangeOfScope.getEnd (), loc));
180
+ auto rangeOfScope = scope->getSourceRangeOfThisASTNode ();
181
+ auto endOfScope =
182
+ Lexer::getLocForEndOfToken (sourceMgr, rangeOfScope.End );
183
+
184
+ loc = translateLocForReplacedRange (sourceMgr, rangeOfScope.Start , loc);
185
+ return isBeforeInSource (
186
+ sourceMgr, endOfScope, loc, /* allowEqual=*/ true );
174
187
});
175
188
176
189
if (child != getChildren ().end ()) {
177
- auto rangeOfScope = (*child)->getCharSourceRangeOfScope (sourceMgr);
178
- loc = translateLocForReplacedRange (sourceMgr, rangeOfScope, loc);
179
- if (rangeOfScope.contains (loc))
190
+ auto rangeOfScope = (*child)->getSourceRangeOfThisASTNode ();
191
+ auto endOfScope = Lexer::getLocForEndOfToken (sourceMgr, rangeOfScope.End );
192
+ loc = translateLocForReplacedRange (sourceMgr, rangeOfScope.Start , loc);
193
+ if (isBeforeInSource (sourceMgr, rangeOfScope.Start , loc,
194
+ /* allowEqual=*/ true ) &&
195
+ isBeforeInSource (sourceMgr, loc, endOfScope, /* allowEqual=*/ false ))
180
196
return *child;
181
197
}
182
198
0 commit comments