Skip to content

Commit 392185e

Browse files
authored
Merge pull request #77721 from rintaro/astgen-virtualfiles
[ASTGen] Handle '#sourceLocation' directives
2 parents 23e3f5f + e153164 commit 392185e

File tree

5 files changed

+121
-1
lines changed

5 files changed

+121
-1
lines changed

include/swift/Basic/BasicBridging.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,18 @@ enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedGeneratedSourceFileKind {
450450
BridgedGeneratedSourceFileKindNone,
451451
};
452452

453+
//===----------------------------------------------------------------------===//
454+
// MARK: VirtualFile
455+
//===----------------------------------------------------------------------===//
456+
457+
struct BridgedVirtualFile {
458+
size_t StartPosition;
459+
size_t EndPosition;
460+
BridgedStringRef Name;
461+
ptrdiff_t LineOffset;
462+
size_t NamePosition;
463+
};
464+
453465
SWIFT_END_NULLABILITY_ANNOTATIONS
454466

455467
#ifndef PURE_BRIDGING_MODE

include/swift/Bridging/ASTGen.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ intptr_t swift_ASTGen_configuredRegions(
9494
void swift_ASTGen_freeConfiguredRegions(
9595
BridgedIfConfigClauseRangeInfo *_Nullable regions, intptr_t numRegions);
9696

97+
size_t
98+
swift_ASTGen_virtualFiles(void *_Nonnull sourceFile,
99+
BridgedVirtualFile *_Nullable *_Nonnull virtualFiles);
100+
void swift_ASTGen_freeBridgedVirtualFiles(
101+
BridgedVirtualFile *_Nullable virtualFiles, size_t numFiles);
102+
97103
#ifdef __cplusplus
98104
}
99105
#endif

lib/ASTGen/Sources/ASTGen/SourceFile.swift

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import SwiftDiagnostics
1515
import SwiftIfConfig
1616
@_spi(ExperimentalLanguageFeatures) import SwiftParser
1717
import SwiftParserDiagnostics
18-
import SwiftSyntax
18+
@_spi(Compiler) import SwiftSyntax
1919

2020
/// Describes a source file that has been "exported" to the C++ part of the
2121
/// compiler, with enough information to interface with the C++ layer.
@@ -299,3 +299,46 @@ public func findSyntaxNodeInSourceFile<Node: SyntaxProtocol>(
299299

300300
return resultSyntax
301301
}
302+
303+
@_cdecl("swift_ASTGen_virtualFiles")
304+
@usableFromInline
305+
func getVirtualFiles(
306+
sourceFilePtr: UnsafeMutableRawPointer,
307+
cVirtualFilesOut: UnsafeMutablePointer<UnsafeMutablePointer<BridgedVirtualFile>?>
308+
) -> Int {
309+
let sourceFilePtr = sourceFilePtr.assumingMemoryBound(to: ExportedSourceFile.self)
310+
let virtualFiles = sourceFilePtr.pointee.sourceLocationConverter.lineTable.virtualFiles
311+
guard !virtualFiles.isEmpty else {
312+
cVirtualFilesOut.pointee = nil
313+
return 0
314+
}
315+
316+
let cArrayBuf: UnsafeMutableBufferPointer<BridgedVirtualFile> = .allocate(capacity: virtualFiles.count)
317+
_ = cArrayBuf.initialize(
318+
from: virtualFiles.lazy.map({ virtualFile in
319+
BridgedVirtualFile(
320+
StartPosition: virtualFile.startPosition.utf8Offset,
321+
EndPosition: virtualFile.endPosition.utf8Offset,
322+
Name: allocateBridgedString(virtualFile.fileName),
323+
LineOffset: virtualFile.lineOffset,
324+
NamePosition: virtualFile.fileNamePosition.utf8Offset
325+
)
326+
})
327+
)
328+
329+
cVirtualFilesOut.pointee = cArrayBuf.baseAddress
330+
return cArrayBuf.count
331+
}
332+
333+
@_cdecl("swift_ASTGen_freeBridgedVirtualFiles")
334+
func freeVirtualFiles(
335+
cVirtualFiles: UnsafeMutablePointer<BridgedVirtualFile>?,
336+
numFiles: Int
337+
) {
338+
let buffer = UnsafeMutableBufferPointer<BridgedVirtualFile>(start: cVirtualFiles, count: numFiles)
339+
for vFile in buffer {
340+
freeBridgedString(bridged: vFile.Name)
341+
}
342+
buffer.deinitialize()
343+
buffer.deallocate()
344+
}

lib/Parse/ParseRequests.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ void appendToVector(BridgedASTNode cNode, void *vecPtr) {
252252
SourceFileParsingResult parseSourceFileViaASTGen(SourceFile &SF) {
253253
ASTContext &Ctx = SF.getASTContext();
254254
DiagnosticEngine &Diags = Ctx.Diags;
255+
SourceManager &SM = Ctx.SourceMgr;
255256
const LangOptions &langOpts = Ctx.LangOpts;
256257
const GeneratedSourceInfo *genInfo = SF.getGeneratedSourceFileInfo();
257258

@@ -264,6 +265,24 @@ SourceFileParsingResult parseSourceFileViaASTGen(SourceFile &SF) {
264265
auto *exportedSourceFile = SF.getExportedSourceFile();
265266
assert(exportedSourceFile && "Couldn't parse via SyntaxParser");
266267

268+
// Collect virtual files.
269+
// FIXME: Avoid side effects in the request.
270+
// FIXME: Do this lazily in SourceManager::getVirtualFile().
271+
BridgedVirtualFile *virtualFiles = nullptr;
272+
size_t numVirtualFiles =
273+
swift_ASTGen_virtualFiles(exportedSourceFile, &virtualFiles);
274+
SourceLoc bufferStart = SM.getLocForBufferStart(SF.getBufferID());
275+
for (size_t i = 0; i != numVirtualFiles; ++i) {
276+
auto &VF = virtualFiles[i];
277+
Ctx.SourceMgr.createVirtualFile(
278+
bufferStart.getAdvancedLoc(VF.StartPosition), VF.Name.unbridged(),
279+
VF.LineOffset, VF.EndPosition - VF.StartPosition);
280+
StringRef name = Ctx.AllocateCopy(VF.Name.unbridged());
281+
SF.VirtualFilePaths.emplace_back(
282+
name, bufferStart.getAdvancedLoc(VF.NamePosition));
283+
}
284+
swift_ASTGen_freeBridgedVirtualFiles(virtualFiles, numVirtualFiles);
285+
267286
// Emit parser diagnostics.
268287
(void)swift_ASTGen_emitParserDiagnostics(
269288
Ctx, &Diags, exportedSourceFile, /*emitOnlyErrors=*/false,

test/ASTGen/sourcelocation.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
func test(arg: Int) -> Int { 1 }
2+
3+
func foo() {
4+
#sourceLocation(file: "first/foo.swift", line: 100)
5+
test(arg: 1)
6+
}
7+
8+
func bar() {
9+
#sourceLocation(file: "second/foo.swift", line: 100)
10+
}
11+
12+
test(arg: 2)
13+
14+
// RUN: %target-swift-frontend -emit-silgen -module-name MyMod %s -enable-experimental-feature ParserASTGen -diagnostic-style llvm \
15+
// RUN: 2>&1 >/dev/null | %FileCheck --enable-windows-compatibility --strict-whitespace %s
16+
17+
// REQUIRES: swift_swift_parser
18+
// REQUIRES: swift_feature_ParserASTGen
19+
20+
// CHECK: {{^}}second/foo.swift:102:1: warning: result of call to 'test(arg:)' is unused
21+
// CHECK-NEXT: {{^}}test(arg: 2)
22+
// CHECK-NEXT: {{^}}^ ~~~~~~~~
23+
24+
// CHECK: {{^}}first/foo.swift:100:3: warning: result of call to 'test(arg:)' is unused
25+
// CHECK-NEXT: {{^}} test(arg: 1)
26+
// CHECK-NEXT: {{^}} ^ ~~~~~~~~
27+
28+
// CHECK: {{^SOURCE_DIR[\//]test[/\\]ASTGen[\//]sourcelocation\.swift}}:4:25: warning: '#sourceLocation' directive produces '#fileID' string of 'MyMod/foo.swift', which conflicts with '#fileID' strings produced by other paths in the module
29+
// CHECK-NEXT: {{^}} #sourceLocation(file: "first/foo.swift", line: 100)
30+
// CHECK-NEXT: {{^}} ^
31+
32+
// CHECK: {{^SOURCE_DIR[\//]test[/\\]ASTGen[\//]sourcelocation\.swift}}:9:25: warning: '#sourceLocation' directive produces '#fileID' string of 'MyMod/foo.swift', which conflicts with '#fileID' strings produced by other paths in the module
33+
// CHECK-NEXT: {{^}} #sourceLocation(file: "second/foo.swift", line: 100)
34+
// CHECK-NEXT: {{^}} ^
35+
36+
// CHECK: {{^SOURCE_DIR[\//]test[/\\]ASTGen[\//]sourcelocation\.swift}}:9:25: note: change file in '#sourceLocation' to 'first/foo.swift'
37+
// CHECK-NEXT: {{^}} #sourceLocation(file: "second/foo.swift", line: 100)
38+
// CHECK-NEXT: {{^}} ^~~~~~~~~~~~~~~~~~
39+
// CHECK-NEXT: {{^}} "first/foo.swift"
40+

0 commit comments

Comments
 (0)