Skip to content

Commit f65a703

Browse files
author
Nathan Hawes
authored
Merge pull request #26354 from nathawes/string-interpolation-doc-structure
[Parse][IDE] Fix document structure request output for interpolated string literals
2 parents 2411be9 + aa0305e commit f65a703

File tree

3 files changed

+42
-5
lines changed

3 files changed

+42
-5
lines changed

lib/IDE/SyntaxModel.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ class ModelASTWalker : public ASTWalker {
242242
const LangOptions &LangOpts;
243243
const SourceManager &SM;
244244
unsigned BufferID;
245+
ASTContext &Ctx;
245246
std::vector<StructureElement> SubStructureStack;
246247
SourceLoc LastLoc;
247248
static const std::regex &getURLRegex(StringRef Protocol);
@@ -262,6 +263,7 @@ class ModelASTWalker : public ASTWalker {
262263
LangOpts(File.getASTContext().LangOpts),
263264
SM(File.getASTContext().SourceMgr),
264265
BufferID(File.getBufferID().getValue()),
266+
Ctx(File.getASTContext()),
265267
Walker(Walker) { }
266268

267269
// FIXME: Remove this
@@ -521,13 +523,14 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
521523
SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, E->getSourceRange());
522524
pushStructureNode(SN, E);
523525
} else if (auto *Tup = dyn_cast<TupleExpr>(E)) {
526+
auto *ParentE = Parent.getAsExpr();
524527
if (isCurrentCallArgExpr(Tup)) {
525528
for (unsigned I = 0; I < Tup->getNumElements(); ++ I) {
526529
SourceLoc NameLoc = Tup->getElementNameLoc(I);
527530
if (NameLoc.isValid())
528531
passTokenNodesUntil(NameLoc, PassNodesBehavior::ExcludeNodeAtLocation);
529532
}
530-
} else {
533+
} else if (!ParentE || !isa<InterpolatedStringLiteralExpr>(ParentE)) {
531534
SyntaxStructureNode SN;
532535
SN.Kind = SyntaxStructureKind::TupleExpression;
533536
SN.Range = charSourceRangeFromSourceRange(SM, Tup->getSourceRange());
@@ -562,6 +565,18 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
562565
subExpr->walk(*this);
563566
}
564567
return { false, walkToExprPost(SE) };
568+
} else if (auto *ISL = dyn_cast<InterpolatedStringLiteralExpr>(E)) {
569+
// Don't visit the child expressions directly. Instead visit the arguments
570+
// of each appendStringLiteral/appendInterpolation CallExpr so we don't
571+
// try to output structure nodes for those calls.
572+
llvm::SaveAndRestore<ASTWalker::ParentTy> SetParent(Parent, E);
573+
ISL->forEachSegment(Ctx, [&](bool isInterpolation, CallExpr *CE) {
574+
if (isInterpolation) {
575+
if (auto *Arg = CE->getArg())
576+
Arg->walk(*this);
577+
}
578+
});
579+
return { false, walkToExprPost(E) };
565580
}
566581

567582
return { true, E };
@@ -1166,7 +1181,8 @@ bool ModelASTWalker::shouldPassBraceStructureNode(BraceStmt *S) {
11661181
return (!dyn_cast_or_null<AbstractFunctionDecl>(Parent.getAsDecl()) &&
11671182
!dyn_cast_or_null<TopLevelCodeDecl>(Parent.getAsDecl()) &&
11681183
!dyn_cast_or_null<CaseStmt>(Parent.getAsStmt()) &&
1169-
S->getSourceRange().isValid());
1184+
S->getSourceRange().isValid() &&
1185+
!S->isImplicit());
11701186
}
11711187

11721188
ModelASTWalker::PassUntilResult

lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,7 +1916,6 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
19161916

19171917
// The start location of the entire string literal.
19181918
SourceLoc Loc = Tok.getLoc();
1919-
SourceLoc EndLoc = Loc.getAdvancedLoc(Tok.getLength());
19201919

19211920
StringRef OpenDelimiterStr, OpenQuoteStr, CloseQuoteStr, CloseDelimiterStr;
19221921
unsigned DelimiterLength = Tok.getCustomDelimiterLen();
@@ -2036,8 +2035,8 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
20362035
Status = parseStringSegments(Segments, EntireTok, InterpolationVar,
20372036
Stmts, LiteralCapacity, InterpolationCount);
20382037

2039-
auto Body = BraceStmt::create(Context, Loc, Stmts, EndLoc,
2040-
/*implicit=*/false);
2038+
auto Body = BraceStmt::create(Context, Loc, Stmts, /*endLoc=*/Loc,
2039+
/*implicit=*/true);
20412040
AppendingExpr = new (Context) TapExpr(nullptr, Body);
20422041
}
20432042

test/IDE/structure.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,5 +306,27 @@ enum FooEnum {
306306
}
307307
// CHECK: }</enum>
308308

309+
firstCall("\(1)", 1)
310+
// CHECK: <call><name>firstCall</name>(<arg>"\(1)"</arg>, <arg>1</arg>)</call>
311+
312+
secondCall("\(a: {struct Foo {let x = 10}; return Foo().x}())", 1)
313+
// CHECK: <call><name>secondCall</name>(<arg>"\(a: <call><name><closure><brace>{<struct>struct <name>Foo</name> {<property>let <name>x</name> = 10</property>}</struct>; return <call><name>Foo</name>()</call>.x}</brace></closure></name>()</call>)"</arg>, <arg>1</arg>)</call>
314+
315+
thirdCall("""
316+
\("""
317+
\({
318+
return a()
319+
}())
320+
""")
321+
""")
322+
// CHECK: <call><name>thirdCall</name>("""
323+
// CHECK-NEXT: \("""
324+
// CHECK-NEXT: \(<call><name><closure>{
325+
// CHECK-NEXT: return <call><name>a</name>()</call>
326+
// CHECK-NEXT: }</closure></name>()</call>)
327+
// CHECK-NEXT: """)
328+
// CHECK-NEXT: """)</call>
329+
309330
fourthCall(a: @escaping () -> Int)
310331
// CHECK: <call><name>fourthCall</name>(<arg><name>a</name>: @escaping () -> Int</arg>)</call>
332+

0 commit comments

Comments
 (0)