Skip to content

Commit 71cdfff

Browse files
authored
Merge pull request #40064 from apple/es-imports
2 parents 940322b + e7577ce commit 71cdfff

10 files changed

+348
-22
lines changed

include/swift/AST/Decl.h

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,13 +1132,16 @@ class ImportDecl final : public Decl,
11321132

11331133
SourceLoc ImportLoc;
11341134
SourceLoc KindLoc;
1135+
/// Used to store the real module name corresponding to this import decl in
1136+
/// case module aliasing is used. For example if '-module-alias Foo=Bar' was
1137+
/// passed and this decl is 'import Foo', the real name 'Bar' will be stored.
1138+
Identifier RealModuleName;
11351139

11361140
/// The resolved module.
11371141
ModuleDecl *Mod = nullptr;
11381142

11391143
ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K,
11401144
SourceLoc KindLoc, ImportPath Path);
1141-
11421145
public:
11431146
static ImportDecl *create(ASTContext &C, DeclContext *DC,
11441147
SourceLoc ImportLoc, ImportKind Kind,
@@ -1162,15 +1165,57 @@ class ImportDecl final : public Decl,
11621165
return static_cast<ImportKind>(Bits.ImportDecl.ImportKind);
11631166
}
11641167

1168+
/// Retrieves the import path as written in the source code.
1169+
///
1170+
/// \returns An \c ImportPath corresponding to this import decl. If module aliasing
1171+
/// was used, this will contain the aliased name of the module; for instance,
1172+
/// if you wrote 'import Foo' but passed '-module-alias Foo=Bar', this import
1173+
/// path will include 'Foo'. This return value is always owned by \c ImportDecl
1174+
/// (which is owned by the AST context), so it can be persisted.
11651175
ImportPath getImportPath() const {
11661176
return ImportPath({ getTrailingObjects<ImportPath::Element>(),
11671177
static_cast<size_t>(Bits.ImportDecl.NumPathElements) });
11681178
}
11691179

1180+
/// Retrieves the import path, replacing any module aliases with real names.
1181+
///
1182+
/// \param scratch An \c ImportPath::Builder which may, if necessary, be used to
1183+
/// construct the return value. It may go unused, so you should not try to
1184+
/// read the result from it; use the return value instead.
1185+
/// \returns An \c ImportPath corresponding to this import decl. If module aliasing
1186+
/// was used, this will contain the real name of the module; for instance,
1187+
/// if you wrote 'import Foo' but passed '-module-alias Foo=Bar', this import
1188+
/// path will include 'Bar'. This return value may be owned by \p scratch,
1189+
/// so it should not be used after \p scratch is destroyed.
1190+
ImportPath getRealImportPath(ImportPath::Builder &scratch) const;
1191+
1192+
/// Retrieves the part of the import path that contains the module name,
1193+
/// as written in the source code.
1194+
///
1195+
/// \returns A \c ImportPath::Module corresponding to this import decl. If module
1196+
/// aliasing was used, this will contain the aliased name of the module; for
1197+
/// instance, if you wrote 'import Foo' but passed '-module-alias Foo=Bar',
1198+
/// this module path will contain 'Foo'. This return value is always owned by
1199+
/// \c ImportDecl (which is owned by the AST context), so it can be persisted.
11701200
ImportPath::Module getModulePath() const {
11711201
return getImportPath().getModulePath(getImportKind());
11721202
}
11731203

1204+
/// Retrieves the part of the import path that contains the module name,
1205+
/// replacing any module aliases with real names.
1206+
///
1207+
/// \param scratch An \c ImportPath::Builder which may, if necessary, be used to
1208+
/// construct the return value. It may go unused, so you should not try to
1209+
/// read the result from it; use the return value instead.
1210+
/// \returns An \c ImportPath::Module corresponding to this import decl. If module
1211+
/// aliasing was used, this will contain the real name of the module; for
1212+
/// instance, if you wrote 'import Foo' but passed '-module-alias Foo=Bar',
1213+
/// the returned path will contain 'Bar'. This return value may be owned
1214+
/// by \p scratch, so it should not be used after \p scratch is destroyed.
1215+
ImportPath::Module getRealModulePath(ImportPath::Builder &scratch) const {
1216+
return getRealImportPath(scratch).getModulePath(getImportKind());
1217+
}
1218+
11741219
ImportPath::Access getAccessPath() const {
11751220
return getImportPath().getAccessPath(getImportKind());
11761221
}

lib/AST/ASTDumper.cpp

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

523523
OS << " '";
524-
ID->getImportPath().print(OS);
524+
// Check if module aliasing was used for the given imported module; for
525+
// example, if '-module-alias Foo=Bar' was passed and this module has
526+
// 'import Foo', its corresponding real module name 'Bar' should be printed.
527+
ImportPath::Builder scratch;
528+
ID->getRealImportPath(scratch).print(OS);
525529
OS << "')";
526530
}
527531

@@ -1223,7 +1227,7 @@ void swift::printContext(raw_ostream &os, DeclContext *dc) {
12231227

12241228
switch (dc->getContextKind()) {
12251229
case DeclContextKind::Module:
1226-
printName(os, cast<ModuleDecl>(dc)->getName());
1230+
printName(os, cast<ModuleDecl>(dc)->getRealName());
12271231
break;
12281232

12291233
case DeclContextKind::FileUnit:
@@ -1304,11 +1308,13 @@ void ValueDecl::dumpRef(raw_ostream &os) const {
13041308
// Print the context.
13051309
printContext(os, getDeclContext());
13061310
os << ".";
1311+
// Print name.
1312+
getName().printPretty(os);
1313+
} else {
1314+
auto moduleName = cast<ModuleDecl>(this)->getRealName();
1315+
os << moduleName;
13071316
}
13081317

1309-
// Print name.
1310-
getName().printPretty(os);
1311-
13121318
// Print location.
13131319
auto &srcMgr = getASTContext().SourceMgr;
13141320
if (getLoc().isValid()) {

lib/AST/Decl.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,11 @@ 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 realNameIfExists = Ctx.getRealModuleName(Path.front().Item,
1070+
ASTContext::ModuleAliasLookupOption::realNameFromAlias);
1071+
if (!realNameIfExists.empty()) {
1072+
D->RealModuleName = realNameIfExists;
1073+
}
10691074
return D;
10701075
}
10711076

@@ -1158,6 +1163,24 @@ ImportDecl::findBestImportKind(ArrayRef<ValueDecl *> Decls) {
11581163
return FirstKind;
11591164
}
11601165

1166+
ImportPath ImportDecl::getRealImportPath(ImportPath::Builder &scratch) const {
1167+
assert(scratch.empty() && "scratch ImportPath::Builder must be initially empty");
1168+
auto path = getImportPath();
1169+
if (RealModuleName.empty())
1170+
return path;
1171+
1172+
for (auto elem : path) {
1173+
if (scratch.empty()) {
1174+
// Add the real module name instead of its alias
1175+
scratch.push_back(RealModuleName);
1176+
} else {
1177+
// Add the rest if any (access path elements)
1178+
scratch.push_back(elem.Item);
1179+
}
1180+
}
1181+
return scratch.get();
1182+
}
1183+
11611184
ArrayRef<ValueDecl *> ImportDecl::getDecls() const {
11621185
// If this isn't a scoped import, there's nothing to do.
11631186
if (getImportKind() == ImportKind::Module)

lib/FrontendTool/ImportedModules.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ bool swift::emitImportedModules(ModuleDecl *mainModule,
6666
if (!ID)
6767
continue;
6868

69-
auto modulePath = ID->getModulePath();
69+
ImportPath::Builder scratch;
70+
auto modulePath = ID->getRealModulePath(scratch);
7071
// only the top-level name is needed (i.e. A in A.B.C)
7172
Modules.insert(modulePath[0].Item.str());
7273
}

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+
}

test/Frontend/module-alias-dump-ast.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
// RUN: %target-swift-frontend -dump-ast %t/FileLib.swift -module-alias XLogging=AppleLogging -I %t > %t/result-ast.output
1414

1515
// RUN: %FileCheck %s -input-file %t/result-ast.output -check-prefix CHECK-AST
16-
// CHECK-AST: XLogging
16+
// CHECK-AST-NOT: bind=XLogging
17+
// CHECK-AST-NOT: module<XLogging>
18+
// CHECK-AST-NOT: decl=XLogging
19+
// CHECK-AST: component id='XLogging' bind=AppleLogging
1720
// CHECK-AST: module<AppleLogging>
18-
21+
// CHECK-AST: decl=AppleLogging
1922

2023
// BEGIN FileLogging.swift
2124
public struct Logger {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/// Test -emit-imported-modules with module aliasing.
2+
///
3+
4+
// RUN: %empty-directory(%t)
5+
// RUN: %{python} %utils/split_file.py -o %t %s
6+
7+
/// Create AppleLogging.swiftmodule by aliasing XLogging
8+
// RUN: %target-swift-frontend -module-name AppleLogging -module-alias XLogging=AppleLogging %t/FileLogging.swift -emit-module -emit-module-path %t/AppleLogging.swiftmodule
9+
// RUN: test -f %t/AppleLogging.swiftmodule
10+
11+
/// Verify emitted imported modules contains AppleLogging as a module name
12+
// RUN: %target-swift-frontend -emit-imported-modules %t/FileLib1.swift -module-alias XLogging=AppleLogging -I %t > %t/result1.output
13+
14+
// RUN: %FileCheck %s -input-file %t/result1.output -check-prefix CHECK-AST1
15+
// CHECK-AST1-NOT: XLogging
16+
// CHECK-AST1: AppleLogging
17+
18+
// RUN: %target-swift-frontend -emit-imported-modules %t/FileLib2.swift -module-alias XLogging=AppleLogging -I %t > %t/result2.output
19+
20+
// RUN: %FileCheck %s -input-file %t/result2.output -check-prefix CHECK-AST2
21+
// CHECK-AST2-NOT: XLogging
22+
// CHECK-AST2: AppleLogging
23+
24+
25+
// BEGIN FileLogging.swift
26+
public struct Logger {
27+
public init() {}
28+
}
29+
public func setup() -> XLogging.Logger? {
30+
return Logger()
31+
}
32+
33+
// BEGIN FileLib1.swift
34+
import XLogging
35+
36+
public func start() -> XLogging.Logger? {
37+
return XLogging.setup()
38+
}
39+
40+
public func end(_ arg: XLogging.Logger) {
41+
}
42+
43+
// BEGIN FileLib2.swift
44+
import struct XLogging.Logger
45+
46+
public func start() -> XLogging.Logger? {
47+
return XLogging.Logger()
48+
}

0 commit comments

Comments
 (0)