Skip to content

Commit 17b87a1

Browse files
author
Nathan Hawes
authored
Merge pull request #27186 from nathawes/fix-doc-structure-for-interpolated-strings
[5.1][IDE] Fix document structure request output for interpolated string literals
2 parents 279ca88 + 3721e45 commit 17b87a1

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

lib/IDE/SyntaxModel.cpp

Lines changed: 16 additions & 1 deletion
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
void visitSourceFile(SourceFile &SrcFile, ArrayRef<SyntaxNode> Tokens);
@@ -513,13 +515,14 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
513515
SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, E->getSourceRange());
514516
pushStructureNode(SN, E);
515517
} else if (auto *Tup = dyn_cast<TupleExpr>(E)) {
518+
auto *ParentE = Parent.getAsExpr();
516519
if (isCurrentCallArgExpr(Tup)) {
517520
for (unsigned I = 0; I < Tup->getNumElements(); ++ I) {
518521
SourceLoc NameLoc = Tup->getElementNameLoc(I);
519522
if (NameLoc.isValid())
520523
passTokenNodesUntil(NameLoc, PassNodesBehavior::ExcludeNodeAtLocation);
521524
}
522-
} else {
525+
} else if (!ParentE || !isa<InterpolatedStringLiteralExpr>(ParentE)) {
523526
SyntaxStructureNode SN;
524527
SN.Kind = SyntaxStructureKind::TupleExpression;
525528
SN.Range = charSourceRangeFromSourceRange(SM, Tup->getSourceRange());
@@ -554,6 +557,18 @@ std::pair<bool, Expr *> ModelASTWalker::walkToExprPre(Expr *E) {
554557
subExpr->walk(*this);
555558
}
556559
return { false, walkToExprPost(SE) };
560+
} else if (auto *ISL = dyn_cast<InterpolatedStringLiteralExpr>(E)) {
561+
// Don't visit the child expressions directly. Instead visit the arguments
562+
// of each appendStringLiteral/appendInterpolation CallExpr so we don't
563+
// try to output structure nodes for those calls.
564+
llvm::SaveAndRestore<ASTWalker::ParentTy> SetParent(Parent, E);
565+
ISL->forEachSegment(Ctx, [&](bool isInterpolation, CallExpr *CE) {
566+
if (isInterpolation) {
567+
if (auto *Arg = CE->getArg())
568+
Arg->walk(*this);
569+
}
570+
});
571+
return { false, walkToExprPost(E) };
557572
}
558573

559574
return { true, E };

test/IDE/structure.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,39 @@ myFunc(foo: 0,
293293
bar: baz == 0)
294294
// CHECK: <call><name>myFunc</name>(<arg><name>foo</name>: 0</arg>,
295295
// CHECK: <arg><name>bar</name>: baz == 0</arg>)</call>
296+
297+
298+
enum FooEnum {
299+
// CHECK: <enum>enum <name>FooEnum</name> {
300+
case blah(x: () -> () = {
301+
// CHECK: <enum-case>case <enum-elem><name>blah(<param><name>x</name>: <type>() -> ()</type> = <closure><brace>{
302+
@Tuples func foo(x: MyStruc) {}
303+
// CHECK: @Tuples <ffunc>func <name>foo(<param><name>x</name>: <type>MyStruc</type></param>)</name> {}</ffunc>
304+
})
305+
// CHECK: }</brace></closure></param>)</name></enum-elem></enum-case>
306+
}
307+
// CHECK: }</enum>
308+
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+
330+
fourthCall(a: @escaping () -> Int)
331+
// CHECK: <call><name>fourthCall</name>(<arg><name>a</name>: @escaping () -> Int</arg>)</call>

0 commit comments

Comments
 (0)