Skip to content

Commit 49eb4d6

Browse files
committed
[IDE] Check whether an AST node contains the IDE inspection point based on CharSourceRange
This fixes an issue if the range ends with a string literal that contains the IDE inspection target. In that case the end of the range will point to the start of the string literal but the IDE inspection target is inside the string literal and thus after the range’s end.
1 parent f210a8e commit 49eb4d6

File tree

9 files changed

+63
-28
lines changed

9 files changed

+63
-28
lines changed

include/swift/Basic/SourceManager.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,17 +214,26 @@ class SourceManager {
214214
(isBeforeInBuffer(R.Start, Loc) && isBeforeInBuffer(Loc, R.End));
215215
}
216216

217+
/// Returns true if range \c R contains the location \c Loc. The location
218+
/// \c Loc should point at the beginning of the token.
219+
bool rangeContainsTokenLoc(CharSourceRange R, SourceLoc Loc) const {
220+
return Loc == R.getStart() || Loc == R.getEnd() ||
221+
(isBeforeInBuffer(R.getStart(), Loc) &&
222+
isBeforeInBuffer(Loc, R.getEnd()));
223+
}
224+
217225
/// Returns true if range \c Enclosing contains the range \c Inner.
218226
bool rangeContains(SourceRange Enclosing, SourceRange Inner) const {
219227
return rangeContainsTokenLoc(Enclosing, Inner.Start) &&
220228
rangeContainsTokenLoc(Enclosing, Inner.End);
221229
}
222230

223231
/// Returns true if range \p R contains the code-completion location, if any.
224-
bool rangeContainsIDEInspectionTarget(SourceRange R) const {
225-
return IDEInspectionTargetBufferID
226-
? rangeContainsTokenLoc(R, getIDEInspectionTargetLoc())
227-
: false;
232+
bool rangeContainsIDEInspectionTarget(CharSourceRange R) const {
233+
if (!IDEInspectionTargetBufferID) {
234+
return false;
235+
}
236+
return rangeContainsTokenLoc(R, getIDEInspectionTargetLoc());
228237
}
229238

230239
/// Returns the buffer ID for the specified *valid* location.

include/swift/Sema/IDETypeChecking.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,13 @@ namespace swift {
355355
SmallVector<std::pair<ValueDecl *, ValueDecl *>, 1>
356356
getShorthandShadows(LabeledConditionalStmt *CondStmt,
357357
DeclContext *DC = nullptr);
358+
359+
/// Returns \c true` if \p range is valid and contains the IDE inspection
360+
/// target. This performs the underlying check based on \c CharSourceRange
361+
/// to make sure we correctly return \c true if the ide inspection target
362+
/// is inside a string literal that's the last token in \p range.
363+
bool containsIDEInspectionTarget(SourceRange range,
364+
const SourceManager &SourceMgr);
358365
}
359366

360367
#endif

lib/AST/Decl.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8166,8 +8166,15 @@ BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {
81668166

81678167
// Don't allow getBody() to trigger parsing of an unparsed body containing the
81688168
// IDE inspection location.
8169+
// FIXME: We should be properly constructing the range of the the body as a
8170+
// CharSourceRange but we can't because we don't have access to the lexer
8171+
// here. Using the end location of the SourceRange works good enough here
8172+
// because the last token is a '}' and the IDE inspection point is not inside
8173+
// the closing brace.
81698174
if (getBodyKind() == BodyKind::Unparsed &&
8170-
ctx.SourceMgr.rangeContainsIDEInspectionTarget(getBodySourceRange())) {
8175+
ctx.SourceMgr.rangeContainsIDEInspectionTarget(
8176+
CharSourceRange(ctx.SourceMgr, getBodySourceRange().Start,
8177+
getBodySourceRange().End))) {
81718178
return nullptr;
81728179
}
81738180

lib/IDE/IDETypeChecking.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,3 +973,11 @@ swift::getShorthandShadows(LabeledConditionalStmt *CondStmt, DeclContext *DC) {
973973
}
974974
return Result;
975975
}
976+
977+
bool swift::containsIDEInspectionTarget(SourceRange range,
978+
const SourceManager &SourceMgr) {
979+
if (range.isInvalid())
980+
return false;
981+
auto charRange = Lexer::getCharSourceRangeFromSourceRange(SourceMgr, range);
982+
return SourceMgr.rangeContainsIDEInspectionTarget(charRange);
983+
}

lib/Parse/ParseDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7986,8 +7986,10 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) {
79867986
auto BodyPreviousLoc = PreviousLoc;
79877987
SourceRange BodyRange(Tok.getLoc());
79887988
auto setIDEInspectionDelayedDeclStateIfNeeded = [&] {
7989+
auto CharBodyRange =
7990+
Lexer::getCharSourceRangeFromSourceRange(SourceMgr, BodyRange);
79897991
if (!isIDEInspectionFirstPass() ||
7990-
!SourceMgr.rangeContainsIDEInspectionTarget(BodyRange)) {
7992+
!SourceMgr.rangeContainsIDEInspectionTarget(CharBodyRange)) {
79917993
return;
79927994
}
79937995
if (State->hasIDEInspectionDelayedDeclState())

lib/Parse/ParseExpr.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,9 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
14331433
assert(activeElements.size() == 1 && activeElements[0].is<Expr *>());
14341434
auto expr = activeElements[0].get<Expr *>();
14351435
ParserStatus status(ICD);
1436-
if (SourceMgr.rangeContainsIDEInspectionTarget(expr->getSourceRange()) &&
1436+
auto charRange = Lexer::getCharSourceRangeFromSourceRange(
1437+
SourceMgr, expr->getSourceRange());
1438+
if (SourceMgr.rangeContainsIDEInspectionTarget(charRange) &&
14371439
L->isCodeCompletion())
14381440
status.setHasCodeCompletion();
14391441
hasBindOptional |= exprsWithBindOptional.contains(expr);
@@ -2826,7 +2828,9 @@ ParserResult<Expr> Parser::parseExprClosure() {
28262828
SmallVector<ASTNode, 4> bodyElements;
28272829
Status |= parseBraceItems(bodyElements, BraceItemListKind::Brace);
28282830

2829-
if (SourceMgr.rangeContainsIDEInspectionTarget({leftBrace, PreviousLoc})) {
2831+
if (SourceMgr.rangeContainsIDEInspectionTarget(
2832+
Lexer::getCharSourceRangeFromSourceRange(SourceMgr,
2833+
{leftBrace, PreviousLoc}))) {
28302834
// Ignore 'IDEInspectionDelayedDeclState' inside closures.
28312835
// Completions inside functions body inside closures at top level should
28322836
// be considered top-level completions.

lib/Sema/BuilderTransform.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "MiscDiagnostics.h"
19-
#include "TypeChecker.h"
2019
#include "TypeCheckAvailability.h"
21-
#include "swift/Sema/IDETypeChecking.h"
20+
#include "TypeChecker.h"
2221
#include "swift/AST/ASTPrinter.h"
2322
#include "swift/AST/ASTVisitor.h"
2423
#include "swift/AST/ASTWalker.h"
@@ -27,14 +26,15 @@
2726
#include "swift/AST/ParameterList.h"
2827
#include "swift/AST/TypeCheckRequests.h"
2928
#include "swift/Sema/ConstraintSystem.h"
29+
#include "swift/Sema/IDETypeChecking.h"
3030
#include "swift/Sema/SolutionResult.h"
3131
#include "llvm/ADT/DenseMap.h"
3232
#include "llvm/ADT/SmallVector.h"
3333
#include <iterator>
3434
#include <map>
3535
#include <memory>
36-
#include <utility>
3736
#include <tuple>
37+
#include <utility>
3838

3939
using namespace swift;
4040
using namespace constraints;

lib/Sema/ConstraintSystem.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/Basic/Statistic.h"
3232
#include "swift/Sema/CSFix.h"
3333
#include "swift/Sema/ConstraintGraph.h"
34+
#include "swift/Sema/IDETypeChecking.h"
3435
#include "swift/Sema/SolutionResult.h"
3536
#include "llvm/ADT/SetVector.h"
3637
#include "llvm/ADT/SmallSet.h"
@@ -353,18 +354,14 @@ ConstraintSystem::getAlternativeLiteralTypes(KnownProtocolKind kind,
353354
}
354355

355356
bool ConstraintSystem::containsIDEInspectionTarget(ASTNode node) const {
356-
SourceRange range = node.getSourceRange();
357-
if (range.isInvalid())
358-
return false;
359-
return Context.SourceMgr.rangeContainsIDEInspectionTarget(range);
357+
return swift::containsIDEInspectionTarget(node.getSourceRange(),
358+
Context.SourceMgr);
360359
}
361360

362361
bool ConstraintSystem::containsIDEInspectionTarget(
363362
const ArgumentList *args) const {
364-
SourceRange range = args->getSourceRange();
365-
if (range.isInvalid())
366-
return false;
367-
return Context.SourceMgr.rangeContainsIDEInspectionTarget(range);
363+
return swift::containsIDEInspectionTarget(args->getSourceRange(),
364+
Context.SourceMgr);
368365
}
369366

370367
ConstraintLocator *ConstraintSystem::getConstraintLocator(

lib/Sema/TypeCheckCodeCompletion.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17-
#include "swift/Subsystems.h"
18-
#include "TypeChecker.h"
19-
#include "TypeCheckObjC.h"
20-
#include "TypeCheckType.h"
2117
#include "CodeSynthesis.h"
2218
#include "MiscDiagnostics.h"
23-
#include "swift/AST/ASTWalker.h"
19+
#include "TypeCheckObjC.h"
20+
#include "TypeCheckType.h"
21+
#include "TypeChecker.h"
2422
#include "swift/AST/ASTVisitor.h"
23+
#include "swift/AST/ASTWalker.h"
2524
#include "swift/AST/Attr.h"
2625
#include "swift/AST/DiagnosticSuppression.h"
2726
#include "swift/AST/ExistentialLayout.h"
@@ -37,13 +36,15 @@
3736
#include "swift/AST/Type.h"
3837
#include "swift/AST/TypeCheckRequests.h"
3938
#include "swift/Basic/Defer.h"
40-
#include "swift/Basic/Statistic.h"
4139
#include "swift/Basic/STLExtras.h"
40+
#include "swift/Basic/Statistic.h"
41+
#include "swift/Parse/IDEInspectionCallbacks.h"
4242
#include "swift/Parse/Lexer.h"
43-
#include "swift/Sema/IDETypeChecking.h"
44-
#include "swift/Sema/ConstraintSystem.h"
4543
#include "swift/Sema/CompletionContextFinder.h"
44+
#include "swift/Sema/ConstraintSystem.h"
45+
#include "swift/Sema/IDETypeChecking.h"
4646
#include "swift/Strings.h"
47+
#include "swift/Subsystems.h"
4748
#include "llvm/ADT/DenseMap.h"
4849
#include "llvm/ADT/PointerUnion.h"
4950
#include "llvm/ADT/SmallSet.h"
@@ -565,7 +566,7 @@ bool TypeChecker::typeCheckForCodeCompletion(
565566
{
566567
auto range = target.getSourceRange();
567568
if (range.isInvalid() ||
568-
!Context.SourceMgr.rangeContainsIDEInspectionTarget(range))
569+
!containsIDEInspectionTarget(range, Context.SourceMgr))
569570
return false;
570571
}
571572

0 commit comments

Comments
 (0)