From 0fa39231daa4bb92bbb8ba3a46c701b13d0a33b2 Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 18 Jul 2019 18:21:53 -0400 Subject: [PATCH] Fill in source locations in implicit function builder expressions to satisfy the code-coverage instrumentation. rdar://51612977 --- lib/Sema/BuilderTransform.cpp | 32 ++++++++++++++----- test/IDE/complete_function_builder.swift | 6 ++-- test/Profiler/coverage_function_builder.swift | 31 ++++++++++++++++++ 3 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 test/Profiler/coverage_function_builder.swift diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index 6f9f53a962d78..efb6accf6de05 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -60,8 +60,10 @@ class BuilderClosureVisitor // to get diagnostics if something about this builder call fails, // e.g. if there isn't a matching overload for `buildBlock`. // But we can only do this if there isn't a type variable in the type. - TypeLoc typeLoc(nullptr, - builderType->hasTypeVariable() ? Type() : builderType); + TypeLoc typeLoc; + if (!builderType->hasTypeVariable()) { + typeLoc = TypeLoc(new (ctx) FixedTypeRepr(builderType, loc), builderType); + } auto typeExpr = new (ctx) TypeExpr(typeLoc); if (cs) { @@ -69,10 +71,19 @@ class BuilderClosureVisitor cs->setType(&typeExpr->getTypeLoc(), builderType); } + SmallVector argLabelLocs; + for (auto i : indices(argLabels)) { + argLabelLocs.push_back(args[i]->getStartLoc()); + } + typeExpr->setImplicit(); auto memberRef = new (ctx) UnresolvedDotExpr( typeExpr, loc, fnName, DeclNameLoc(loc), /*implicit=*/true); - return CallExpr::createImplicit(ctx, memberRef, args, argLabels); + SourceLoc openLoc = args.empty() ? loc : args.front()->getStartLoc(); + SourceLoc closeLoc = args.empty() ? loc : args.back()->getEndLoc(); + return CallExpr::create(ctx, memberRef, openLoc, args, + argLabels, argLabelLocs, closeLoc, + /*trailing closure*/ nullptr, /*implicit*/true); } /// Check whether the builder supports the given operation. @@ -400,10 +411,12 @@ class BuilderClosureVisitor auto optionalDecl = ctx.getOptionalDecl(); auto optionalType = optionalDecl->getDeclaredType(); - auto optionalTypeExpr = TypeExpr::createImplicit(optionalType, ctx); + auto loc = arg->getStartLoc(); + auto optionalTypeExpr = + TypeExpr::createImplicitHack(loc, optionalType, ctx); auto someRef = new (ctx) UnresolvedDotExpr( - optionalTypeExpr, SourceLoc(), ctx.getIdentifier("some"), - DeclNameLoc(), /*implicit=*/true); + optionalTypeExpr, loc, ctx.getIdentifier("some"), + DeclNameLoc(loc), /*implicit=*/true); return CallExpr::createImplicit(ctx, someRef, arg, { }); } @@ -411,7 +424,8 @@ class BuilderClosureVisitor auto optionalDecl = ctx.getOptionalDecl(); auto optionalType = optionalDecl->getDeclaredType(); - auto optionalTypeExpr = TypeExpr::createImplicit(optionalType, ctx); + auto optionalTypeExpr = + TypeExpr::createImplicitHack(endLoc, optionalType, ctx); return new (ctx) UnresolvedDotExpr( optionalTypeExpr, endLoc, ctx.getIdentifier("none"), DeclNameLoc(endLoc), /*implicit=*/true); @@ -511,7 +525,9 @@ bool TypeChecker::typeCheckFunctionBuilderFuncBody(FuncDecl *FD, return true; assert(returnExprType->isEqual(returnType)); - auto returnStmt = new (Context) ReturnStmt(SourceLoc(), returnExpr); + auto loc = returnExpr->getStartLoc(); + auto returnStmt = + new (Context) ReturnStmt(loc, returnExpr, /*implicit*/ true); auto origBody = FD->getBody(); auto fakeBody = BraceStmt::create(Context, origBody->getLBraceLoc(), { returnStmt }, diff --git a/test/IDE/complete_function_builder.swift b/test/IDE/complete_function_builder.swift index eb5867e3d4573..985c65fa824ac 100644 --- a/test/IDE/complete_function_builder.swift +++ b/test/IDE/complete_function_builder.swift @@ -3,8 +3,8 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_CLOSURE_COLOR_CONTEXT | %FileCheck %s -check-prefix=IN_CLOSURE_COLOR_CONTEXT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_CLOSURE_COLOR_CONTEXT_DOT | %FileCheck %s -check-prefix=IN_CLOSURE_COLOR_CONTEXT_DOT -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXTUAL_TYPE_1 | %FileCheck %s -check-prefix=CONTEXTUAL_TYPE_INVALID -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXTUAL_TYPE_2 | %FileCheck %s -check-prefix=CONTEXTUAL_TYPE_INVALID +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXTUAL_TYPE_1 | %FileCheck %s -check-prefix=CONTEXTUAL_TYPE_VALID +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXTUAL_TYPE_2 | %FileCheck %s -check-prefix=CONTEXTUAL_TYPE_VALID // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXTUAL_TYPE_3 | %FileCheck %s -check-prefix=CONTEXTUAL_TYPE_VALID // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXTUAL_TYPE_4 | %FileCheck %s -check-prefix=CONTEXTUAL_TYPE_VALID // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXTUAL_TYPE_5 | %FileCheck %s -check-prefix=CONTEXTUAL_TYPE_INVALID @@ -123,11 +123,9 @@ func acceptBuilder(@EnumToVoidBuilder body: () -> Void) {} func testContextualType() { acceptBuilder { -// FIXME: This should suggest enum values. .#^CONTEXTUAL_TYPE_1^# } acceptBuilder { -// FIXME: This should suggest enum values. .#^CONTEXTUAL_TYPE_2^#; .north; } diff --git a/test/Profiler/coverage_function_builder.swift b/test/Profiler/coverage_function_builder.swift new file mode 100644 index 0000000000000..a08237f268eb8 --- /dev/null +++ b/test/Profiler/coverage_function_builder.swift @@ -0,0 +1,31 @@ +// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -profile-generate -profile-coverage-mapping -emit-sorted-sil -emit-sil -module-name coverage_functon_builder %s | %FileCheck %s + +@_functionBuilder +struct Summer { + static func buildBlock(_ x: Int...) -> Int { + return x.reduce(0, +) + } + static func buildIf(_ x: Int?) -> Int { + return x ?? 0 + } +} + +// CHECK-LABEL: sil_coverage_map {{.*}} "$s24coverage_functon_builder5test0SiyF" +@Summer +func test0() -> Int { + // CHECK: [[@LINE-1]]:21 -> [[@LINE+3]]:2 : 0 + 18 + 12 +} + +// CHECK-LABEL: sil_coverage_map {{.*}} "$s24coverage_functon_builder5test1SiyF" +@Summer +func test1() -> Int { + // CHECK: [[@LINE-1]]:21 -> [[@LINE+7]]:2 : 0 + 18 + 12 + if 7 < 23 { + 11 + 8 + } +}