@@ -314,7 +314,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
314
314
}
315
315
}
316
316
317
- private var cachedSourceKitOptions = RequestCache < TextDocumentSourceKitOptionsRequest > ( )
317
+ private var cachedAdjustedSourceKitOptions = RequestCache < TextDocumentSourceKitOptionsRequest > ( )
318
318
319
319
private var cachedBuildTargets = Cache < WorkspaceBuildTargetsRequest , [ BuildTargetIdentifier : BuildTargetInfo ] > ( )
320
320
@@ -518,7 +518,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
518
518
} else {
519
519
nil
520
520
}
521
- self . cachedSourceKitOptions . clear ( isolation: self ) { cacheKey in
521
+ self . cachedAdjustedSourceKitOptions . clear ( isolation: self ) { cacheKey in
522
522
guard let updatedTargets else {
523
523
// All targets might have changed
524
524
return true
@@ -747,13 +747,22 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
747
747
target: target,
748
748
language: language
749
749
)
750
-
751
- let response = try await cachedSourceKitOptions. get ( request, isolation: self ) { request in
752
- try await buildSystemAdapter. send ( request)
750
+ let response = try await cachedAdjustedSourceKitOptions. get ( request, isolation: self ) { request in
751
+ let options = try await buildSystemAdapter. send ( request)
752
+ switch language. semanticKind {
753
+ case . swift:
754
+ return options? . adjustArgsForSemanticSwiftFunctionality ( fileToIndex: document)
755
+ case . clang:
756
+ return options? . adjustingArgsForSemanticClangFunctionality ( )
757
+ default :
758
+ return options
759
+ }
753
760
}
761
+
754
762
guard let response else {
755
763
return nil
756
764
}
765
+
757
766
return FileBuildSettings (
758
767
compilerArguments: response. compilerArguments,
759
768
workingDirectory: response. workingDirectory,
@@ -1228,3 +1237,153 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
1228
1237
private func isDescendant( _ selfPathComponents: [ String ] , of otherPathComponents: [ String ] ) -> Bool {
1229
1238
return selfPathComponents. dropLast ( ) . starts ( with: otherPathComponents)
1230
1239
}
1240
+
1241
+ fileprivate extension TextDocumentSourceKitOptionsResponse {
1242
+ /// Adjust compiler arguments that were created for building to compiler arguments that should be used for indexing
1243
+ /// or background AST builds.
1244
+ ///
1245
+ /// This removes compiler arguments that produce output files and adds arguments to eg. allow errors and index the
1246
+ /// file.
1247
+ func adjustArgsForSemanticSwiftFunctionality( fileToIndex: DocumentURI ) -> TextDocumentSourceKitOptionsResponse {
1248
+ let optionsToRemove : [ CompilerCommandLineOption ] = [
1249
+ . flag( " c " , [ . singleDash] ) ,
1250
+ . flag( " disable-cmo " , [ . singleDash] ) ,
1251
+ . flag( " emit-dependencies " , [ . singleDash] ) ,
1252
+ . flag( " emit-module-interface " , [ . singleDash] ) ,
1253
+ . flag( " emit-module " , [ . singleDash] ) ,
1254
+ . flag( " emit-objc-header " , [ . singleDash] ) ,
1255
+ . flag( " incremental " , [ . singleDash] ) ,
1256
+ . flag( " no-color-diagnostics " , [ . singleDash] ) ,
1257
+ . flag( " parseable-output " , [ . singleDash] ) ,
1258
+ . flag( " save-temps " , [ . singleDash] ) ,
1259
+ . flag( " serialize-diagnostics " , [ . singleDash] ) ,
1260
+ . flag( " use-frontend-parseable-output " , [ . singleDash] ) ,
1261
+ . flag( " validate-clang-modules-once " , [ . singleDash] ) ,
1262
+ . flag( " whole-module-optimization " , [ . singleDash] ) ,
1263
+ . flag( " experimental-skip-all-function-bodies " , frontendName: " Xfrontend " , [ . singleDash] ) ,
1264
+ . flag( " experimental-skip-non-inlinable-function-bodies " , frontendName: " Xfrontend " , [ . singleDash] ) ,
1265
+ . flag( " experimental-skip-non-exportable-decls " , frontendName: " Xfrontend " , [ . singleDash] ) ,
1266
+ . flag( " experimental-lazy-typecheck " , frontendName: " Xfrontend " , [ . singleDash] ) ,
1267
+
1268
+ . option( " clang-build-session-file " , [ . singleDash] , [ . separatedBySpace] ) ,
1269
+ . option( " emit-module-interface-path " , [ . singleDash] , [ . separatedBySpace] ) ,
1270
+ . option( " emit-module-path " , [ . singleDash] , [ . separatedBySpace] ) ,
1271
+ . option( " emit-objc-header-path " , [ . singleDash] , [ . separatedBySpace] ) ,
1272
+ . option( " emit-package-module-interface-path " , [ . singleDash] , [ . separatedBySpace] ) ,
1273
+ . option( " emit-private-module-interface-path " , [ . singleDash] , [ . separatedBySpace] ) ,
1274
+ . option( " num-threads " , [ . singleDash] , [ . separatedBySpace] ) ,
1275
+ // Technically, `-o` and the output file don't need to be separated by a space. Eg. `swiftc -oa file.swift` is
1276
+ // valid and will write to an output file named `a`.
1277
+ // We can't support that because the only way to know that `-output-file-map` is a different flag and not an option
1278
+ // to write to an output file named `utput-file-map` is to know all compiler arguments of `swiftc`, which we don't.
1279
+ . option( " o " , [ . singleDash] , [ . separatedBySpace] ) ,
1280
+ . option( " output-file-map " , [ . singleDash] , [ . separatedBySpace, . separatedByEqualSign] ) ,
1281
+ ]
1282
+
1283
+ var result : [ String ] = [ ]
1284
+ result. reserveCapacity ( compilerArguments. count)
1285
+ var iterator = compilerArguments. makeIterator ( )
1286
+ while let argument = iterator. next ( ) {
1287
+ switch optionsToRemove. firstMatch ( for: argument) {
1288
+ case . removeOption:
1289
+ continue
1290
+ case . removeOptionAndNextArgument:
1291
+ _ = iterator. next ( )
1292
+ continue
1293
+ case . removeOptionAndPreviousArgument( let name) :
1294
+ if let previousArg = result. last, previousArg. hasSuffix ( " - \( name) " ) {
1295
+ _ = result. popLast ( )
1296
+ }
1297
+ continue
1298
+ case nil :
1299
+ break
1300
+ }
1301
+ result. append ( argument)
1302
+ }
1303
+
1304
+ result += [
1305
+ // Avoid emitting the ABI descriptor, we don't need it
1306
+ " -Xfrontend " , " -empty-abi-descriptor " ,
1307
+ ]
1308
+
1309
+ result += supplementalClangIndexingArgs. flatMap { [ " -Xcc " , $0] }
1310
+
1311
+ return TextDocumentSourceKitOptionsResponse ( compilerArguments: result, workingDirectory: workingDirectory)
1312
+ }
1313
+
1314
+ /// Adjust compiler arguments that were created for building to compiler arguments that should be used for indexing
1315
+ /// or background AST builds.
1316
+ ///
1317
+ /// This removes compiler arguments that produce output files and adds arguments to eg. typecheck only.
1318
+ func adjustingArgsForSemanticClangFunctionality( ) -> TextDocumentSourceKitOptionsResponse {
1319
+ let optionsToRemove : [ CompilerCommandLineOption ] = [
1320
+ // Disable writing of a depfile
1321
+ . flag( " M " , [ . singleDash] ) ,
1322
+ . flag( " MD " , [ . singleDash] ) ,
1323
+ . flag( " MMD " , [ . singleDash] ) ,
1324
+ . flag( " MG " , [ . singleDash] ) ,
1325
+ . flag( " MM " , [ . singleDash] ) ,
1326
+ . flag( " MV " , [ . singleDash] ) ,
1327
+ // Don't create phony targets
1328
+ . flag( " MP " , [ . singleDash] ) ,
1329
+ // Don't write out compilation databases
1330
+ . flag( " MJ " , [ . singleDash] ) ,
1331
+ // Don't compile
1332
+ . flag( " c " , [ . singleDash] ) ,
1333
+
1334
+ . flag( " fmodules-validate-once-per-build-session " , [ . singleDash] ) ,
1335
+
1336
+ // Disable writing of a depfile
1337
+ . option( " MT " , [ . singleDash] , [ . noSpace, . separatedBySpace] ) ,
1338
+ . option( " MF " , [ . singleDash] , [ . noSpace, . separatedBySpace] ) ,
1339
+ . option( " MQ " , [ . singleDash] , [ . noSpace, . separatedBySpace] ) ,
1340
+
1341
+ // Don't write serialized diagnostic files
1342
+ . option( " serialize-diagnostics " , [ . singleDash, . doubleDash] , [ . separatedBySpace] ) ,
1343
+
1344
+ . option( " fbuild-session-file " , [ . singleDash] , [ . separatedByEqualSign] ) ,
1345
+ ]
1346
+
1347
+ var result : [ String ] = [ ]
1348
+ result. reserveCapacity ( compilerArguments. count)
1349
+ var iterator = compilerArguments. makeIterator ( )
1350
+ while let argument = iterator. next ( ) {
1351
+ switch optionsToRemove. firstMatch ( for: argument) {
1352
+ case . removeOption:
1353
+ continue
1354
+ case . removeOptionAndNextArgument:
1355
+ _ = iterator. next ( )
1356
+ continue
1357
+ case . removeOptionAndPreviousArgument( let name) :
1358
+ if let previousArg = result. last, previousArg. hasSuffix ( " - \( name) " ) {
1359
+ _ = result. popLast ( )
1360
+ }
1361
+ continue
1362
+ case nil :
1363
+ break
1364
+ }
1365
+ result. append ( argument)
1366
+ }
1367
+ result += supplementalClangIndexingArgs
1368
+ result. append (
1369
+ " -fsyntax-only "
1370
+ )
1371
+ return TextDocumentSourceKitOptionsResponse ( compilerArguments: result, workingDirectory: workingDirectory)
1372
+ }
1373
+ }
1374
+
1375
+ fileprivate let supplementalClangIndexingArgs : [ String ] = [
1376
+ // Retain extra information for indexing
1377
+ " -fretain-comments-from-system-headers " ,
1378
+ // Pick up macro definitions during indexing
1379
+ " -Xclang " , " -detailed-preprocessing-record " ,
1380
+
1381
+ // libclang uses 'raw' module-format. Match it so we can reuse the module cache and PCHs that libclang uses.
1382
+ " -Xclang " , " -fmodule-format=raw " ,
1383
+
1384
+ // Be less strict - we want to continue and typecheck/index as much as possible
1385
+ " -Xclang " , " -fallow-pch-with-compiler-errors " ,
1386
+ " -Xclang " , " -fallow-pcm-with-compiler-errors " ,
1387
+ " -Wno-non-modular-include-in-framework-module " ,
1388
+ " -Wno-incomplete-umbrella " ,
1389
+ ]
0 commit comments