Skip to content

Commit c607fea

Browse files
committed
Ensure REPL arguments are processed by the ArgsResolver
Introduce a new Job.ArgTemplate case which represents "squashed" arguments, so we can represent the structure of LLDB's --repl= argument and resolve the args which will be used to configure the frontend before concatenating them.
1 parent de31343 commit c607fea

File tree

7 files changed

+52
-14
lines changed

7 files changed

+52
-14
lines changed

Sources/SwiftDriver/Execution/ArgsResolver.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,15 @@ public final class ArgsResolver {
6767
return try lock.withLock {
6868
return try unsafeResolve(path: path)
6969
}
70+
7071
case .responseFilePath(let path):
7172
return "@\(try resolve(.path(path)))"
73+
7274
case let .joinedOptionAndPath(option, path):
7375
return option + (try resolve(.path(path)))
76+
77+
case let .squashedArgumentList(option: option, args: args):
78+
return try option + args.map{ try resolve($0) }.joined(separator: " ")
7479
}
7580
}
7681

Sources/SwiftDriver/Jobs/CommandLineArguments.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ extension Array where Element == Job.ArgTemplate {
162162
}
163163

164164
/// A shell-escaped string representation of the arguments, as they would appear on the command line.
165-
public var joinedArguments: String {
165+
/// Note: does not resolve arguments.
166+
public var joinedUnresolvedArguments: String {
166167
return self.map {
167168
switch $0 {
168169
case .flag(let string):
@@ -173,6 +174,8 @@ extension Array where Element == Job.ArgTemplate {
173174
return "@\(path.name.spm_shellEscaped())"
174175
case let .joinedOptionAndPath(option, path):
175176
return option.spm_shellEscaped() + path.name.spm_shellEscaped()
177+
case let .squashedArgumentList(option, args):
178+
return (option + args.joinedUnresolvedArguments).spm_shellEscaped()
176179
}
177180
}.joined(separator: " ")
178181
}

Sources/SwiftDriver/Jobs/Job.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public struct Job: Codable, Equatable, Hashable {
4949

5050
/// Represents a joined option+path combo.
5151
case joinedOptionAndPath(String, VirtualPath)
52+
53+
/// Represents a list of arguments squashed together and passed as a single argument.
54+
case squashedArgumentList(option: String, args: [ArgTemplate])
5255
}
5356

5457
/// The Swift module this job involves.
@@ -234,11 +237,15 @@ extension Job.Kind {
234237

235238
extension Job.ArgTemplate: Codable {
236239
private enum CodingKeys: String, CodingKey {
237-
case flag, path, responseFilePath, joinedOptionAndPath
240+
case flag, path, responseFilePath, joinedOptionAndPath, squashedArgumentList
238241

239242
enum JoinedOptionAndPathCodingKeys: String, CodingKey {
240243
case option, path
241244
}
245+
246+
enum SquashedArgumentListCodingKeys: String, CodingKey {
247+
case option, args
248+
}
242249
}
243250

244251
public func encode(to encoder: Encoder) throws {
@@ -259,6 +266,12 @@ extension Job.ArgTemplate: Codable {
259266
forKey: .joinedOptionAndPath)
260267
try keyedContainer.encode(option, forKey: .option)
261268
try keyedContainer.encode(path, forKey: .path)
269+
case .squashedArgumentList(option: let option, args: let args):
270+
var keyedContainer = container.nestedContainer(
271+
keyedBy: CodingKeys.SquashedArgumentListCodingKeys.self,
272+
forKey: .squashedArgumentList)
273+
try keyedContainer.encode(option, forKey: .option)
274+
try keyedContainer.encode(args, forKey: .args)
262275
}
263276
}
264277

@@ -286,6 +299,12 @@ extension Job.ArgTemplate: Codable {
286299
forKey: .joinedOptionAndPath)
287300
self = .joinedOptionAndPath(try keyedValues.decode(String.self, forKey: .option),
288301
try keyedValues.decode(VirtualPath.self, forKey: .path))
302+
case .squashedArgumentList:
303+
let keyedValues = try values.nestedContainer(
304+
keyedBy: CodingKeys.SquashedArgumentListCodingKeys.self,
305+
forKey: .squashedArgumentList)
306+
self = .squashedArgumentList(option: try keyedValues.decode(String.self, forKey: .option),
307+
args: try keyedValues.decode([Job.ArgTemplate].self, forKey: .args))
289308
}
290309
}
291310
}

Sources/SwiftDriver/Jobs/ReplJob.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ extension Driver {
2222
try commandLine.appendAll(.l, .framework, .L, from: &parsedOptions)
2323

2424
// Squash important frontend options into a single argument for LLDB.
25-
let lldbArg = "--repl=\(commandLine.joinedArguments)"
25+
let lldbCommandLine: [Job.ArgTemplate] = [.squashedArgumentList(option: "--repl=", args: commandLine)]
2626
return Job(
2727
moduleName: moduleOutputInfo.name,
2828
kind: .repl,
2929
tool: .absolute(try toolchain.getToolPath(.lldb)),
30-
commandLine: [Job.ArgTemplate.flag(lldbArg)],
30+
commandLine: lldbCommandLine,
3131
inputs: inputs,
3232
primaryInputs: [],
3333
outputs: [],

Sources/SwiftDriverExecution/SwiftDriverExecutor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public final class SwiftDriverExecutor: DriverExecutor {
8686

8787
if usedResponseFile {
8888
// Print the response file arguments as a comment.
89-
result += " # \(job.commandLine.joinedArguments)"
89+
result += " # \(job.commandLine.joinedUnresolvedArguments)"
9090
}
9191

9292
if !job.extraEnvironment.isEmpty {

Tests/SwiftDriverTests/JobExecutorTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,18 @@ final class JobExecutorTests: XCTestCase {
330330
}
331331
}
332332

333+
func testResolveSquashedArgs() throws {
334+
try withTemporaryDirectory { path in
335+
let resolver = try ArgsResolver(fileSystem: localFileSystem, temporaryDirectory: .absolute(path))
336+
let tmpPath = VirtualPath.temporaryWithKnownContents(.init("one.txt"), "hello, world!".data(using: .utf8)!)
337+
let tmpPath2 = VirtualPath.temporaryWithKnownContents(.init("two.txt"), "goodbye!".data(using: .utf8)!)
338+
let resolvedCommandLine = try resolver.resolve(
339+
.squashedArgumentList(option: "--opt=", args: [.path(tmpPath), .path(tmpPath2)]))
340+
XCTAssertEqual(resolvedCommandLine, "--opt=\(path.appending(component: "one.txt").pathString) \(path.appending(component: "two.txt").pathString)")
341+
XCTAssertEqual(resolvedCommandLine.spm_shellEscaped(), "'--opt=\(path.appending(component: "one.txt").pathString) \(path.appending(component: "two.txt").pathString)'")
342+
}
343+
}
344+
333345
func testSaveTemps() throws {
334346
do {
335347
try withTemporaryDirectory { path in

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,7 +1600,7 @@ final class SwiftDriverTests: XCTestCase {
16001600
let plannedJobs = try driver1.planBuild().removingAutolinkExtractJobs()
16011601
XCTAssertEqual(plannedJobs.count, 2)
16021602
XCTAssertEqual(plannedJobs[0].kind, .compile)
1603-
print(plannedJobs[0].commandLine.joinedArguments)
1603+
print(plannedJobs[0].commandLine.joinedUnresolvedArguments)
16041604
XCTAssert(plannedJobs[0].commandLine.contains(.flag("-supplementary-output-file-map")))
16051605
}
16061606

@@ -1795,10 +1795,9 @@ final class SwiftDriverTests: XCTestCase {
17951795
throw XCTSkip()
17961796
}
17971797

1798-
func isLLDBREPLFlag(_ arg: Job.ArgTemplate) -> Bool {
1799-
if case .flag(let replString) = arg {
1800-
return replString.hasPrefix("--repl=") &&
1801-
!replString.contains("-module-name")
1798+
func isExpectedLLDBREPLFlag(_ arg: Job.ArgTemplate) -> Bool {
1799+
if case let .squashedArgumentList(option: opt, args: args) = arg {
1800+
return opt == "--repl=" && !args.contains("-module-name")
18021801
}
18031802
return false
18041803
}
@@ -1810,7 +1809,7 @@ final class SwiftDriverTests: XCTestCase {
18101809
let replJob = plannedJobs.first!
18111810
XCTAssertTrue(replJob.tool.name.contains("lldb"))
18121811
XCTAssertTrue(replJob.requiresInPlaceExecution)
1813-
XCTAssert(replJob.commandLine.contains(where: { isLLDBREPLFlag($0) }))
1812+
XCTAssert(replJob.commandLine.contains(where: { isExpectedLLDBREPLFlag($0) }))
18141813
}
18151814

18161815
do {
@@ -1820,7 +1819,7 @@ final class SwiftDriverTests: XCTestCase {
18201819
let replJob = plannedJobs.first!
18211820
XCTAssertTrue(replJob.tool.name.contains("lldb"))
18221821
XCTAssertTrue(replJob.requiresInPlaceExecution)
1823-
XCTAssert(replJob.commandLine.contains(where: { isLLDBREPLFlag($0) }))
1822+
XCTAssert(replJob.commandLine.contains(where: { isExpectedLLDBREPLFlag($0) }))
18241823
}
18251824

18261825
do {
@@ -1832,7 +1831,7 @@ final class SwiftDriverTests: XCTestCase {
18321831
let replJob = plannedJobs.first!
18331832
XCTAssertTrue(replJob.tool.name.contains("lldb"))
18341833
XCTAssertTrue(replJob.requiresInPlaceExecution)
1835-
XCTAssert(replJob.commandLine.contains(where: { isLLDBREPLFlag($0) }))
1834+
XCTAssert(replJob.commandLine.contains(where: { isExpectedLLDBREPLFlag($0) }))
18361835
}
18371836

18381837
do {
@@ -4286,7 +4285,7 @@ private extension Array where Element == Job.ArgTemplate {
42864285
switch $0 {
42874286
case let .path(path):
42884287
return path.basename == basename
4289-
case .flag, .responseFilePath, .joinedOptionAndPath:
4288+
case .flag, .responseFilePath, .joinedOptionAndPath, .squashedArgumentList:
42904289
return false
42914290
}
42924291
}

0 commit comments

Comments
 (0)