Skip to content

Commit a8472ad

Browse files
authored
Merge pull request swiftlang#133 from benlangmuir/clang-argv0
[clangd] Set correct argv[0] for clangd to fix c++ header search
2 parents 7bfde0f + 57e3404 commit a8472ad

File tree

5 files changed

+58
-9
lines changed

5 files changed

+58
-9
lines changed

Sources/SourceKit/SourceKitServer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,8 @@ public func languageService(
556556
switch language {
557557

558558
case .c, .cpp, .objective_c, .objective_cpp:
559-
guard let clangd = toolchain.clangd else { return nil }
560-
return try makeJSONRPCClangServer(client: client, clangd: clangd, buildSettings: (client as? SourceKitServer)?.workspace?.buildSettings)
559+
guard toolchain.clangd != nil else { return nil }
560+
return try makeJSONRPCClangServer(client: client, toolchain: toolchain, buildSettings: (client as? SourceKitServer)?.workspace?.buildSettings)
561561

562562
case .swift:
563563
guard let sourcekitd = toolchain.sourcekitd else { return nil }

Sources/SourceKit/clangd/ClangLanguageServer.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ final class ClangLanguageServerShim: LanguageServer {
2626

2727
let buildSystem: BuildSystem
2828

29+
let clang: AbsolutePath?
30+
2931
/// Creates a language server for the given client using the sourcekitd dylib at the specified path.
30-
public init(client: Connection, clangd: Connection, buildSystem: BuildSystem) throws {
32+
public init(client: Connection, clangd: Connection, buildSystem: BuildSystem, clang: AbsolutePath?) throws {
3133

3234
self.clangd = clangd
3335
self.buildSystem = buildSystem
36+
self.clang = clang
3437
super.init(client: client)
3538
}
3639

@@ -106,7 +109,7 @@ extension ClangLanguageServerShim {
106109
if let settings = settings {
107110
clangd.send(DidChangeConfiguration(settings: .clangd(
108111
ClangWorkspaceSettings(
109-
compilationDatabaseChanges: [url.path: ClangCompileCommand(settings)]))))
112+
compilationDatabaseChanges: [url.path: ClangCompileCommand(settings, clang: clang)]))))
110113
}
111114

112115
clangd.send(note.params)
@@ -121,7 +124,11 @@ extension ClangLanguageServerShim {
121124
}
122125
}
123126

124-
func makeJSONRPCClangServer(client: MessageHandler, clangd: AbsolutePath, buildSettings: BuildSystem?) throws -> Connection {
127+
func makeJSONRPCClangServer(client: MessageHandler, toolchain: Toolchain, buildSettings: BuildSystem?) throws -> Connection {
128+
129+
guard let clangd = toolchain.clangd else {
130+
preconditionFailure("missing clang from toolchain \(toolchain.identifier)")
131+
}
125132

126133
let clientToServer: Pipe = Pipe()
127134
let serverToClient: Pipe = Pipe()
@@ -137,8 +144,8 @@ func makeJSONRPCClangServer(client: MessageHandler, clangd: AbsolutePath, buildS
137144
let shim = try ClangLanguageServerShim(
138145
client: connectionToClient,
139146
clangd: connection,
140-
buildSystem: buildSettings ?? BuildSystemList()
141-
)
147+
buildSystem: buildSettings ?? BuildSystemList(),
148+
clang: toolchain.clang)
142149

143150
connectionToShim.start(handler: shim)
144151
connectionToClient.start(handler: client)
@@ -172,10 +179,10 @@ func makeJSONRPCClangServer(client: MessageHandler, clangd: AbsolutePath, buildS
172179
}
173180

174181
extension ClangCompileCommand {
175-
init(_ settings: FileBuildSettings) {
182+
init(_ settings: FileBuildSettings, clang: AbsolutePath?) {
176183
// Clang expects the first argument to be the program name, like argv.
177184
self.init(
178-
compilationCommand: ["clang"] + settings.compilerArguments,
185+
compilationCommand: [clang?.pathString ?? "clang"] + settings.compilerArguments,
179186
workingDirectory: settings.workingDirectory ?? "")
180187
}
181188
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"clang_flags": ["-fno-modules", "-Wunused-variable"],
3+
"sources": ["std_header_canary.cpp"]
4+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Note: tests generally should avoid including system headers
2+
// to keep them fast and portable. This test is specifically
3+
// ensuring clangd can find libc++ and builtin headers.
4+
5+
#include <cstdint>
6+
7+
void test() {
8+
uint64_t /*unused_b*/b;
9+
}

Tests/SourceKitTests/LocalClangTests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,33 @@ final class LocalClangTests: XCTestCase {
141141
let resp = try! sk.sendSync(FoldingRangeRequest(textDocument: TextDocumentIdentifier(url)))
142142
XCTAssertNil(resp)
143143
}
144+
145+
146+
func testClangStdHeaderCanary() throws {
147+
guard let ws = try staticSourceKitTibsWorkspace(name: "ClangStdHeaderCanary") else { return }
148+
if ToolchainRegistry.shared.default?.clangd == nil { return }
149+
150+
let loc = ws.testLoc("unused_b")
151+
152+
let expectation = XCTestExpectation(description: "diagnostics")
153+
154+
ws.sk.handleNextNotification { (note: Notification<PublishDiagnostics>) in
155+
XCTAssertEqual(note.params.diagnostics, [
156+
Diagnostic(
157+
range: Position(loc) ..< Position(line: loc.line - 1, utf16index: loc.column),
158+
severity: .warning,
159+
source: nil,
160+
message: "Unused variable 'b'")
161+
])
162+
163+
expectation.fulfill()
164+
}
165+
166+
try ws.openDocument(loc.url, language: .cpp)
167+
168+
let result = XCTWaiter.wait(for: [expectation], timeout: 15)
169+
if result != .completed {
170+
fatalError("error \(result) waiting for diagnostics notification")
171+
}
172+
}
144173
}

0 commit comments

Comments
 (0)