|
30 | 30 | #include "swift/AST/TypeRepr.h" |
31 | 31 | #include "swift/Basic/STLExtras.h" |
32 | 32 | #include "llvm/Support/Compiler.h" |
33 | | -#include <algorithm> |
34 | 33 |
|
35 | 34 | using namespace swift; |
36 | 35 | using namespace namelookup; |
@@ -82,6 +81,15 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( |
82 | 81 | // Someday, just use the assertion below. For now, print out lots of info for |
83 | 82 | // debugging. |
84 | 83 | if (!startingScope) { |
| 84 | + |
| 85 | + // Be lenient in code completion mode. There are cases where the decl |
| 86 | + // context doesn't match with the ASTScope. e.g. dangling attributes. |
| 87 | + // FIXME: Create ASTScope tree even for invalid code. |
| 88 | + if (innermost && |
| 89 | + startingContext->getASTContext().SourceMgr.hasCodeCompletionBuffer()) { |
| 90 | + return innermost; |
| 91 | + } |
| 92 | + |
85 | 93 | llvm::errs() << "ASTScopeImpl: resorting to startingScope hack, file: " |
86 | 94 | << sourceFile->getFilename() << "\n"; |
87 | 95 | // The check is costly, and inactive lookups will end up here, so don't |
@@ -143,33 +151,40 @@ bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const { |
143 | 151 | return true; |
144 | 152 | } |
145 | 153 |
|
| 154 | +/// If the \p loc is in a new buffer but \p range is not, consider the location |
| 155 | +/// is at the start of replaced range. Otherwise, returns \p loc as is. |
| 156 | +static SourceLoc translateLocForReplacedRange(SourceManager &sourceMgr, |
| 157 | + SourceRange range, |
| 158 | + SourceLoc loc) { |
| 159 | + if (const auto &replacedRange = sourceMgr.getReplacedRange()) { |
| 160 | + if (sourceMgr.rangeContainsTokenLoc(replacedRange.New, loc) && |
| 161 | + !sourceMgr.rangeContains(replacedRange.New, range)) { |
| 162 | + return replacedRange.Original.Start; |
| 163 | + } |
| 164 | + } |
| 165 | + return loc; |
| 166 | +} |
| 167 | + |
146 | 168 | NullablePtr<ASTScopeImpl> |
147 | 169 | ASTScopeImpl::findChildContaining(SourceLoc loc, |
148 | 170 | SourceManager &sourceMgr) const { |
149 | 171 | // Use binary search to find the child that contains this location. |
150 | | - struct CompareLocs { |
151 | | - SourceManager &sourceMgr; |
152 | | - |
153 | | - bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { |
154 | | - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); |
155 | | - return -1 == ASTScopeImpl::compare(scope->getSourceRangeOfScope(), loc, |
156 | | - sourceMgr, |
157 | | - /*ensureDisjoint=*/false); |
158 | | - } |
159 | | - bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { |
160 | | - ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); |
161 | | - // Alternatively, we could check that loc < start-of-scope |
162 | | - return 0 >= ASTScopeImpl::compare(loc, scope->getSourceRangeOfScope(), |
163 | | - sourceMgr, |
164 | | - /*ensureDisjoint=*/false); |
165 | | - } |
166 | | - }; |
167 | | - auto *const *child = std::lower_bound( |
168 | | - getChildren().begin(), getChildren().end(), loc, CompareLocs{sourceMgr}); |
169 | | - |
170 | | - if (child != getChildren().end() && |
171 | | - sourceMgr.rangeContainsTokenLoc((*child)->getSourceRangeOfScope(), loc)) |
172 | | - return *child; |
| 172 | + auto *const *child = llvm::lower_bound( |
| 173 | + getChildren(), loc, |
| 174 | + [&sourceMgr](const ASTScopeImpl *scope, SourceLoc loc) { |
| 175 | + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); |
| 176 | + auto rangeOfScope = scope->getSourceRangeOfScope(); |
| 177 | + loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); |
| 178 | + return -1 == ASTScopeImpl::compare(rangeOfScope, loc, sourceMgr, |
| 179 | + /*ensureDisjoint=*/false); |
| 180 | + }); |
| 181 | + |
| 182 | + if (child != getChildren().end()) { |
| 183 | + auto rangeOfScope = (*child)->getSourceRangeOfScope(); |
| 184 | + loc = translateLocForReplacedRange(sourceMgr, rangeOfScope, loc); |
| 185 | + if (sourceMgr.rangeContainsTokenLoc(rangeOfScope, loc)) |
| 186 | + return *child; |
| 187 | + } |
173 | 188 |
|
174 | 189 | return nullptr; |
175 | 190 | } |
|
0 commit comments