Skip to content

Commit 9328d34

Browse files
committed
Allow module aliases to use escaped identifiers as the alias name.
The original module names themselves must still be valid unescaped identifiers; most of the serialization logic in the compiler depends on the name of a module matching its name on the file system, and it would be very complex to turn escaped identifiers into file-safe names.
1 parent b535a88 commit 9328d34

File tree

7 files changed

+152
-6
lines changed

7 files changed

+152
-6
lines changed

include/swift/Parse/Lexer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,10 @@ class Lexer {
395395
/// identifier, without escaping characters.
396396
static bool isIdentifier(StringRef identifier);
397397

398+
/// Determines if the given string is a valid non-operator
399+
/// identifier if it were surrounded by backticks.
400+
static bool isValidAsEscapedIdentifier(StringRef identifier);
401+
398402
/// Determine the token kind of the string, given that it is a valid
399403
/// non-operator identifier. Return tok::identifier if the string is not a
400404
/// reserved word.

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -821,10 +821,13 @@ bool ModuleAliasesConverter::computeModuleAliases(std::vector<std::string> args,
821821
// ModuleAliasMap should initially be empty as setting
822822
// it should be called only once
823823
options.ModuleAliasMap.clear();
824-
825-
auto validate = [&options, &diags](StringRef value, bool allowModuleName) -> bool
826-
{
827-
if (!allowModuleName) {
824+
825+
// validatingModuleName should be true if validating the alias target (an
826+
// actual module name), or true if validating the alias name (which can be
827+
// an escaped identifier).
828+
auto validate = [&options, &diags](StringRef value,
829+
bool validatingModuleName) -> bool {
830+
if (!validatingModuleName) {
828831
if (value == options.ModuleName ||
829832
value == options.ModuleABIName ||
830833
value == options.ModuleLinkName ||
@@ -833,13 +836,14 @@ bool ModuleAliasesConverter::computeModuleAliases(std::vector<std::string> args,
833836
return false;
834837
}
835838
}
836-
if (!Lexer::isIdentifier(value)) {
839+
if ((validatingModuleName && !Lexer::isIdentifier(value)) ||
840+
!Lexer::isValidAsEscapedIdentifier(value)) {
837841
diags.diagnose(SourceLoc(), diag::error_bad_module_name, value, false);
838842
return false;
839843
}
840844
return true;
841845
};
842-
846+
843847
for (auto item: args) {
844848
auto str = StringRef(item);
845849
// splits to an alias and its real name

lib/Parse/Lexer.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,17 @@ bool Lexer::isIdentifier(StringRef string) {
634634
return p == end;
635635
}
636636

637+
bool Lexer::isValidAsEscapedIdentifier(StringRef string) {
638+
if (string.empty())
639+
return false;
640+
char const *p = string.data(), *end = string.end();
641+
if (!advanceIfValidEscapedIdentifier(p, end))
642+
return false;
643+
while (p < end && advanceIfValidEscapedIdentifier(p, end))
644+
;
645+
return p == end;
646+
}
647+
637648
/// Determines if the given string is a valid operator identifier,
638649
/// without escaping characters.
639650
bool Lexer::isOperator(StringRef string) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -module-alias "//my/project:uncommon_name=CommonName" -typecheck -I %S/Inputs/custom-modules %s -Rmodule-loading 2> %t/load-result.output
3+
4+
// RUN: %FileCheck %s -input-file %t/load-result.output -check-prefix CHECK-FOO
5+
// CHECK-FOO: import `//my/project:uncommon_name`
6+
// CHECK-FOO-NEXT: remark: loaded module 'CommonName'
7+
8+
import `//my/project:uncommon_name`
9+
10+
_ = MyStruct()
11+
_ = `//my/project:uncommon_name`.MyStruct()

test/ClangImporter/module-alias.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -module-alias UncommonName=CommonName -typecheck -I %S/Inputs/custom-modules %s -Rmodule-loading 2> %t/load-result.output
3+
4+
// RUN: %FileCheck %s -input-file %t/load-result.output -check-prefix CHECK-FOO
5+
// CHECK-FOO: import UncommonName
6+
// CHECK-FOO-NEXT: remark: loaded module 'CommonName'
7+
8+
import UncommonName
9+
10+
_ = MyStruct()
11+
_ = UncommonName.MyStruct()
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/// Test the -module-alias flag with an escaped identifier alias.
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %{python} %utils/split_file.py -o %t %s
5+
6+
/// Create a module Bar
7+
// RUN: %target-swift-frontend -module-name Bar %t/FileBar.swift -emit-module -emit-module-path %t/Bar.swiftmodule
8+
9+
/// Check Bar.swiftmodule is created
10+
// RUN: test -f %t/Bar.swiftmodule
11+
12+
/// Create a module Foo that imports `//my/project:cat` with -module-alias "//my/project:cat=Bar" with a serialized module loader
13+
// RUN: %target-swift-frontend -module-name Foo %t/FileFoo.swift -module-alias "//my/project:cat=Bar" -I %t -emit-module -emit-module-path %t/Foo.swiftmodule -Rmodule-loading 2> %t/load-result-foo.output
14+
15+
/// Check Foo.swiftmodule is created and Bar.swiftmodule is loaded
16+
// RUN: test -f %t/Foo.swiftmodule
17+
// RUN: test -f %t/Bar.swiftmodule
18+
// RUN: not test -f %t/*cat.swiftmodule
19+
20+
// RUN: %FileCheck %s -input-file %t/load-result-foo.output -check-prefix CHECK-FOO
21+
// CHECK-FOO: remark: loaded module {{.*}}Bar.swiftmodule
22+
23+
/// Create a module Zoo that imports `//my/project:cat` with -module-alias "//my/project:cat=Bar" with a source loader
24+
// RUN: %target-swift-frontend -module-name Zoo %t/FileFoo.swift -module-alias "//my/project:cat=Bar" -I %t -emit-module -emit-module-path %t/Zoo.swiftmodule -enable-source-import -Rmodule-loading 2> %t/load-result-zoo.output
25+
26+
// RUN: test -f %t/Zoo.swiftmodule
27+
// RUN: test -f %t/Bar.swiftmodule
28+
// RUN: not test -f %t/*cat.swiftmodule
29+
30+
// RUN: %FileCheck %s -input-file %t/load-result-zoo.output -check-prefix CHECK-ZOO
31+
// CHECK-ZOO: remark: loaded module {{.*}}Bar.swiftmodule
32+
33+
34+
// BEGIN FileBar.swift
35+
public func bar() {}
36+
37+
// BEGIN FileFoo.swift
38+
import `//my/project:cat`
39+
40+
`//my/project:cat`.bar()
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/// Test the -module-alias flag with an escaped identifier and the explicit module loader.
2+
// UNSUPPORTED: OS=windows-msvc
3+
// RUN: %empty-directory(%t)
4+
// RUN: mkdir -p %t/inputs
5+
// RUN: mkdir -p %t/outputs
6+
7+
/// Create a module Bar
8+
// RUN: echo 'public func bar() {}' > %t/inputs/FileBar.swift
9+
// RUN: %target-swift-frontend -module-name Bar %t/inputs/FileBar.swift -emit-module -emit-module-path %t/inputs/Bar.swiftmodule
10+
// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/SwiftShims.pcm
11+
// RUN: %target-swift-emit-pcm -module-name _SwiftConcurrencyShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/_SwiftConcurrencyShims.pcm
12+
13+
/// Check Bar.swiftmodule is created
14+
// RUN: test -f %t/inputs/Bar.swiftmodule
15+
16+
/// Next create an explicit module dependency map to build module Foo
17+
// RUN: echo 'import `//my/project:cat`' > %t/inputs/FileFoo.swift
18+
19+
// RUN: echo "[{" > %/t/inputs/map.json
20+
// RUN: echo "\"moduleName\": \"Bar\"," >> %/t/inputs/map.json
21+
// RUN: echo "\"modulePath\": \"%/t/inputs/Bar.swiftmodule\"," >> %/t/inputs/map.json
22+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
23+
// RUN: echo "}," >> %/t/inputs/map.json
24+
// RUN: echo "{" >> %/t/inputs/map.json
25+
// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json
26+
// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json
27+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
28+
// RUN: echo "}," >> %/t/inputs/map.json
29+
// RUN: echo "{" >> %/t/inputs/map.json
30+
// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json
31+
// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json
32+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
33+
// RUN: echo "}," >> %/t/inputs/map.json
34+
// RUN: echo "{" >> %/t/inputs/map.json
35+
// RUN: echo "\"moduleName\": \"_Concurrency\"," >> %/t/inputs/map.json
36+
// RUN: echo "\"modulePath\": \"%/concurrency_module\"," >> %/t/inputs/map.json
37+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
38+
// RUN: echo "}," >> %/t/inputs/map.json
39+
// RUN: echo "{" >> %/t/inputs/map.json
40+
// RUN: echo "\"moduleName\": \"SwiftShims\"," >> %/t/inputs/map.json
41+
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
42+
// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %/t/inputs/map.json
43+
// RUN: echo "\"clangModulePath\": \"%t/inputs/SwiftShims.pcm\"" >> %/t/inputs/map.json
44+
// RUN: echo "}," >> %/t/inputs/map.json
45+
// RUN: echo "{" >> %/t/inputs/map.json
46+
// RUN: echo "\"moduleName\": \"_SwiftConcurrencyShims\"," >> %/t/inputs/map.json
47+
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
48+
// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %/t/inputs/map.json
49+
// RUN: echo "\"clangModulePath\": \"%t/inputs/_SwiftConcurrencyShims.pcm\"" >> %/t/inputs/map.json
50+
// RUN: echo "}," >> %/t/inputs/map.json
51+
// RUN: echo "{" >> %/t/inputs/map.json
52+
// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %/t/inputs/map.json
53+
// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %/t/inputs/map.json
54+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
55+
// RUN: echo "}]" >> %/t/inputs/map.json
56+
57+
/// Create a module Foo that imports `//my/project:cat` with -module-alias "//my/project:cat=Bar" with an explicit module loader
58+
// RUN: %target-swift-frontend -module-name Foo %t/inputs/FileFoo.swift -module-alias "//my/project:cat=Bar" -I %t/inputs -emit-module -emit-module-path %t/outputs/Foo.swiftmodule -disable-implicit-swift-modules -explicit-swift-module-map-file %t/inputs/map.json -Rmodule-loading 2> %t/outputs/load-result.output
59+
60+
// RUN: test -f %t/outputs/Foo.swiftmodule
61+
// RUN: test -f %t/inputs/Bar.swiftmodule
62+
// RUN: not test -f %t/inputs/*cat.swiftmodule
63+
64+
// RUN: %FileCheck %s -input-file %t/outputs/load-result.output -check-prefix CHECK
65+
// CHECK: remark: loaded module {{.*}}Bar.swiftmodule

0 commit comments

Comments
 (0)