Skip to content

Commit c08e7b9

Browse files
committed
Module aliasing: modify ImportPath getters to return real module names
Resolves rdar://83632921, rdar://83633109
1 parent a24d74b commit c08e7b9

File tree

7 files changed

+231
-10
lines changed

7 files changed

+231
-10
lines changed

include/swift/AST/Decl.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,13 +1132,14 @@ class ImportDecl final : public Decl,
11321132

11331133
SourceLoc ImportLoc;
11341134
SourceLoc KindLoc;
1135+
Identifier RealModuleName;
11351136

11361137
/// The resolved module.
11371138
ModuleDecl *Mod = nullptr;
11381139

11391140
ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K,
11401141
SourceLoc KindLoc, ImportPath Path);
1141-
1142+
void setRealModuleName(Identifier name) { RealModuleName = name; };
11421143
public:
11431144
static ImportDecl *create(ASTContext &C, DeclContext *DC,
11441145
SourceLoc ImportLoc, ImportKind Kind,
@@ -1162,12 +1163,28 @@ class ImportDecl final : public Decl,
11621163
return static_cast<ImportKind>(Bits.ImportDecl.ImportKind);
11631164
}
11641165

1165-
ImportPath getImportPath() const {
1166-
return ImportPath({ getTrailingObjects<ImportPath::Element>(),
1166+
ImportPath getImportPath(bool withRealModuleName = false) const {
1167+
auto path = ImportPath({ getTrailingObjects<ImportPath::Element>(),
11671168
static_cast<size_t>(Bits.ImportDecl.NumPathElements) });
1169+
if (withRealModuleName && !RealModuleName.empty()) {
1170+
ImportPath::Builder realPath;
1171+
for (auto elem: path) {
1172+
if (realPath.empty()) {
1173+
realPath.push_back(RealModuleName);
1174+
} else {
1175+
realPath.push_back(elem.Item);
1176+
}
1177+
}
1178+
path = ImportPath(realPath.get().getRaw());
1179+
}
1180+
return path;
11681181
}
11691182

1170-
ImportPath::Module getModulePath() const {
1183+
ImportPath::Module getModulePath(bool withRealName = false) const {
1184+
if (withRealName && !RealModuleName.empty()) {
1185+
ImportPath::Module::Builder builder(RealModuleName);
1186+
return builder.get();
1187+
}
11711188
return getImportPath().getModulePath(getImportKind());
11721189
}
11731190

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ namespace {
521521
OS << " kind=" << getImportKindString(ID->getImportKind());
522522

523523
OS << " '";
524-
ID->getImportPath().print(OS);
524+
ID->getImportPath(/*withRealModuleName=*/true).print(OS);
525525
OS << "')";
526526
}
527527

lib/AST/Decl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,8 @@ ImportDecl *ImportDecl::create(ASTContext &Ctx, DeclContext *DC,
10661066
auto D = new (ptr) ImportDecl(DC, ImportLoc, Kind, KindLoc, Path);
10671067
if (ClangN)
10681068
D->setClangNode(ClangN);
1069+
auto realName = Ctx.getRealModuleName(Path.front().Item);
1070+
D->setRealModuleName(realName);
10691071
return D;
10701072
}
10711073

lib/FrontendTool/ImportedModules.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ bool swift::emitImportedModules(ModuleDecl *mainModule,
6565
auto ID = dyn_cast<ImportDecl>(D);
6666
if (!ID)
6767
continue;
68-
69-
auto modulePath = ID->getModulePath();
68+
auto modulePath = ID->getModulePath(/*withRealModuleName=*/true);
7069
// only the top-level name is needed (i.e. A in A.B.C)
7170
Modules.insert(modulePath[0].Item.str());
7271
}

test/Frontend/Inputs/invalid-module-alias.swift

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
public struct Logger {
2+
public init() {}
3+
@_spi(Usable) public func spiFunc() {}
4+
public func regularFunc() {}
5+
func internalFunc() {}
6+
private func privateFunc() {}
7+
}
8+
struct InternalLogger {
9+
init() {}
10+
}
11+
private struct PrivateLogger {
12+
init() {}
13+
}
14+
public func setup() -> XLogging.Logger? {
15+
return Logger()
16+
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
2+
/// Test various import attributes with module aliasing.
3+
///
4+
/// Module 'Lib' imports module 'XLogging' via module aliasing and with various import attributes.
5+
/// Module 'User' imports 'Lib'.
6+
7+
// RUN: %empty-directory(%t)
8+
// RUN: %{python} %utils/split_file.py -o %t %s
9+
10+
/// Create AppleLogging.swiftmodule by aliasing XLogging
11+
// RUN: %target-swift-frontend -module-name AppleLogging -module-alias XLogging=AppleLogging %t/FileLogging.swift -emit-module -emit-module-path %t/AppleLogging.swiftmodule
12+
// RUN: test -f %t/AppleLogging.swiftmodule
13+
14+
/// Below, compile module Lib that imports XLogging with various import attributes via
15+
/// -module-alias XLogging=AppleLogging
16+
17+
/// Test @_spi: Should fail
18+
// RUN: not %target-swift-frontend -module-name Lib1 %t/FileLib1.swift -module-alias XLogging=AppleLogging -I %t -emit-module -emit-module-path %t/Lib1.swiftmodule 2> %t/result-Lib1.output
19+
// RUN: %FileCheck %s -input-file %t/result-Lib1.output -check-prefix CHECK-SPI-ERROR
20+
// CHECK-SPI-ERROR: error: 'spiFunc' is inaccessible due to '@_spi' protection level
21+
22+
/// Test @_spi: Should pass by adding @_spi
23+
// RUN: %target-swift-frontend -module-name Lib2 %t/FileLib2.swift -module-alias XLogging=AppleLogging -I %t -emit-module -emit-module-path %t/Lib2.swiftmodule
24+
// RUN: test -f %t/Lib2.swiftmodule
25+
// RUN: llvm-bcanalyzer -dump %t/Lib2.swiftmodule > %t/Lib2.dump.txt
26+
// RUN: %FileCheck -check-prefix=CHECK-REAL-NAME %s < %t/Lib2.dump.txt
27+
// CHECK-REAL-NAME: AppleLogging
28+
// RUN: not %FileCheck -check-prefix=CHECK-ALIAS %s < %t/Lib2.dump.txt
29+
// CHECK-ALIAS: XLogging
30+
31+
/// Test @_implementationOnly: Should fail
32+
// RUN: not %target-swift-frontend -module-name Lib3 %t/FileLib3.swift -module-alias XLogging=AppleLogging -I %t -emit-module -emit-module-path %t/Lib3.swiftmodule 2> %t/result-Lib3.output
33+
// RUN: %FileCheck %s -input-file %t/result-Lib3.output -check-prefix CHECK-IMPL-ERROR
34+
// CHECK-IMPL-ERROR: error: cannot use module 'XLogging' here; 'XLogging' has been imported as implementation-only
35+
36+
37+
/// Test @_private: Should pass
38+
39+
/// Create AppleLoggingEnablePrivate.swiftmodule by aliasing XLogging
40+
// RUN: %target-swift-frontend -module-name AppleLoggingEnablePrivate -module-alias XLogging=AppleLoggingEnablePrivate %S/Inputs/module-alias-src.swift -emit-module -emit-module-path %t/AppleLoggingEnablePrivate.swiftmodule -enable-private-imports -enable-implicit-dynamic
41+
// RUN: test -f %t/AppleLoggingEnablePrivate.swiftmodule
42+
43+
// RUN: %target-swift-frontend -module-name Lib4 %t/FileLib4.swift -module-alias XLogging=AppleLoggingEnablePrivate -I %t -emit-module -emit-module-path %t/Lib4.swiftmodule
44+
// RUN: llvm-bcanalyzer -dump %t/Lib4.swiftmodule > %t/Lib4.dump.txt
45+
// RUN: %FileCheck -check-prefix=CHECK-REAL-NAME4 %s < %t/Lib4.dump.txt
46+
// CHECK-REAL-NAME4: AppleLoggingEnablePrivate
47+
// RUN: not %FileCheck -check-prefix=CHECK-ALIAS4 %s < %t/Lib4.dump.txt
48+
// CHECK-ALIAS4: XLogging
49+
50+
/// Test @testable: Should pass
51+
52+
/// Create AppleLoggingEnableTesting.swiftmodule by aliasing XLogging
53+
// RUN: %target-swift-frontend -module-name AppleLoggingEnableTesting -module-alias XLogging=AppleLoggingEnableTesting %t/FileLogging.swift -emit-module -emit-module-path %t/AppleLoggingEnableTesting.swiftmodule -enable-testing
54+
// RUN: test -f %t/AppleLoggingEnableTesting.swiftmodule
55+
56+
// RUN: %target-swift-frontend -module-name Lib5 %t/FileLib5.swift -module-alias XLogging=AppleLoggingEnableTesting -I %t -emit-module -emit-module-path %t/Lib5.swiftmodule
57+
// RUN: llvm-bcanalyzer -dump %t/Lib5.swiftmodule > %t/Lib5.dump.txt
58+
// RUN: %FileCheck -check-prefix=CHECK-REAL-NAME5 %s < %t/Lib5.dump.txt
59+
// CHECK-REAL-NAME5: AppleLoggingEnableTesting
60+
// RUN: not %FileCheck -check-prefix=CHECK-ALIAS5 %s < %t/Lib5.dump.txt
61+
// CHECK-ALIAS5: XLogging
62+
63+
/// Test import struct: Should pass with correct module name reference
64+
// RUN: %target-swift-frontend -module-name Lib6 %t/FileLib6.swift -module-alias XLogging=AppleLogging -I %t -emit-module -emit-module-path %t/Lib6.swiftmodule -c -o %t/Lib6.o
65+
// RUN: llvm-nm --defined-only %t/Lib6.o > %t/Lib6.dump.txt
66+
// RUN: %FileCheck -check-prefix=CHECK-REAL-NAME6 %s < %t/Lib6.dump.txt
67+
// CHECK-REAL-NAME6: s4Lib65start12AppleLogging6LoggerVyF
68+
// RUN: not %FileCheck -check-prefix=CHECK-ALIAS6 %s < %t/Lib6.dump.txt
69+
// CHECK-ALIAS6: XLogging
70+
71+
/// Test canImport
72+
// RUN: %target-swift-frontend -module-name Lib7 %t/FileLib7.swift -module-alias XLogging=AppleLogging -I %t -emit-module -emit-module-path %t/Lib7.swiftmodule -Rmodule-loading 2> %t/Lib7.dump.txt
73+
74+
// RUN: %FileCheck -check-prefix=CHECK-LOAD %s < %t/Lib7.dump.txt
75+
// CHECK-LOAD: AppleLogging.swiftmodule
76+
// RUN: not %FileCheck -check-prefix=CHECK-NOT-LOAD %s < %t/Lib7.dump.txt
77+
// CHECK-NOT-LOAD: XLogging.swiftmodule
78+
79+
/// Test @_exported: Should pass with correct module name reference
80+
// RUN: %target-swift-frontend -module-name Lib %t/FileLib.swift -module-alias XLogging=AppleLogging -I %t -emit-module -emit-module-path %t/Lib.swiftmodule
81+
// RUN: test -f %t/Lib.swiftmodule
82+
// RUN: %target-swift-frontend -module-name User %t/FileUser.swift -I %t -emit-module -emit-module-path %t/User.swiftmodule -c -o %t/User.o
83+
// RUN: test -f %t/User.swiftmodule
84+
85+
// RUN: llvm-nm --defined-only %t/User.o > %t/User.dump.txt
86+
// RUN: %FileCheck -check-prefix=CHECK-REAL-NAME-USER %s < %t/User.dump.txt
87+
// CHECK-REAL-NAME-USER: s4User04MainA0V3use12AppleLogging6LoggerVyF
88+
// RUN: not %FileCheck -check-prefix=CHECK-ALIAS-USER %s < %t/User.dump.txt
89+
// CHECK-ALIAS-USER: XLogging
90+
91+
// BEGIN FileLogging.swift
92+
public struct Logger {
93+
public init() {}
94+
@_spi(Usable) public func spiFunc() {}
95+
public func regularFunc() {}
96+
func internalFunc() {}
97+
private func privateFunc() {}
98+
}
99+
struct InternalLogger {
100+
init() {}
101+
}
102+
private struct PrivateLogger {
103+
init() {}
104+
}
105+
public func setup() -> XLogging.Logger? {
106+
return Logger()
107+
}
108+
109+
// BEGIN FileLib1.swift
110+
import XLogging
111+
112+
public func start() {
113+
let it = Logger()
114+
it.regularFunc()
115+
it.spiFunc() // should fail
116+
}
117+
118+
// BEGIN FileLib2.swift
119+
@_spi(Usable) import XLogging
120+
121+
public func start() {
122+
let it = Logger()
123+
it.regularFunc()
124+
it.spiFunc() // pass
125+
}
126+
127+
// BEGIN FileLib3.swift
128+
@_implementationOnly import XLogging
129+
130+
public func start() -> XLogging.Logger? { // should fail
131+
return Logger()
132+
}
133+
134+
// BEGIN FileLib4.swift
135+
@_private(sourceFile: "module-alias-src.swift")
136+
import XLogging
137+
138+
public func start() {
139+
let x = InternalLogger() // should pass
140+
let y = PrivateLogger() // should pass
141+
Logger().internalFunc() // should pass
142+
Logger().privateFunc() // should pass
143+
print(x, y)
144+
}
145+
146+
// BEGIN FileLib5.swift
147+
@testable import XLogging
148+
149+
public func start() {
150+
let x = InternalLogger() // should pass
151+
print(x)
152+
}
153+
154+
// BEGIN FileLib6.swift
155+
import struct XLogging.Logger // should map to AppleLogging.Logger
156+
157+
public func start() -> XLogging.Logger {
158+
let x = Logger()
159+
x.regularFunc()
160+
return x
161+
}
162+
163+
// BEGIN FileLib7.swift
164+
#if canImport(XLogging)
165+
import XLogging // should map to AppleLogging.Logger
166+
#endif
167+
168+
#if canImport(XLogging)
169+
public func start() -> XLogging.Logger {
170+
return Logger()
171+
}
172+
#endif
173+
public func end() {}
174+
175+
// BEGIN FileLib.swift
176+
@_exported import XLogging
177+
178+
public func start() -> XLogging.Logger? {
179+
return Logger()
180+
}
181+
182+
// BEGIN FileUser.swift
183+
import Lib
184+
185+
public struct MainUser {
186+
public func use() -> Logger {
187+
return Logger() // should map to AppleLogging.Logger
188+
}
189+
}
190+

0 commit comments

Comments
 (0)