From 93132b8ce33a011173f7f98eefc84546eef61317 Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Wed, 8 Dec 2021 18:07:01 -0800 Subject: [PATCH 1/7] Add module aliasing option to swift-ide-test Add module aliasing handling in code complete Resolves rdar://86294338 --- include/swift/Frontend/Frontend.h | 2 + .../ArgsToFrontendOptionsConverter.cpp | 4 + lib/Frontend/CompilerInvocation.cpp | 27 ++++ lib/IDE/CodeCompletion.cpp | 13 +- test/IDE/module-aliasing-code-complete.swift | 128 ++++++++++++++++++ tools/swift-ide-test/swift-ide-test.cpp | 8 ++ 6 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 test/IDE/module-aliasing-code-complete.swift diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 44bf8e550f17c..d4650a291e1f5 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -309,6 +309,8 @@ class CompilerInvocation { return FrontendOpts.ModuleName; } + void setModuleAliasMap(std::vector args); + std::string getOutputFilename() const { return FrontendOpts.InputsAndOutputs.getSingleOutputFilename(); } diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 99a7fdc9e135d..6b3a72542c7e3 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -516,6 +516,10 @@ bool ArgsToFrontendOptionsConverter::setUpImmediateArgs() { bool ArgsToFrontendOptionsConverter::computeModuleAliases() { auto list = Args.getAllArgValues(options::OPT_module_alias); if (!list.empty()) { + // ModuleAliasMap should initially be empty as setting + // it should be called only once + Opts.ModuleAliasMap.clear(); + auto validate = [this](StringRef value, bool allowModuleName) -> bool { if (!allowModuleName) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index abf67e7477d5b..b9d645400a450 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -262,6 +262,33 @@ void CompilerInvocation::setSDKPath(const std::string &Path) { updateRuntimeLibraryPaths(SearchPathOpts, LangOpts.Target); } +// This assumes the param args contains valid strings for module +// aliasing. The full validation of input for aliasing is done at +// ArgsToFrontendOptionsConverter::computeModulealiases. +void CompilerInvocation::setModuleAliasMap(std::vector args) { + // ModuleAliasMap should initially be empty as setting + // it should be called only once + FrontendOpts.ModuleAliasMap.clear(); + for (auto item: args) { + auto str = StringRef(item); + // splits to an alias and the underlying name + auto pair = str.split('='); + auto lhs = pair.first; + auto rhs = pair.second; + if (rhs.empty()) // bad format, so skip to the next + continue; + if (!FrontendOpts.ModuleAliasMap.insert({rhs, StringRef()}).second) { + // the underlying name was already added, so skip + continue; + } + auto underlyingName = FrontendOpts.ModuleAliasMap.find(rhs)->first(); + if (!FrontendOpts.ModuleAliasMap.insert({lhs, underlyingName}).second) { + // the alias was already added, so skip + continue; + } + } +} + static bool ParseFrontendArgs( FrontendOptions &opts, ArgList &args, DiagnosticEngine &diags, SmallVectorImpl> *buffers) { diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 0eedcfb237550..47701a6accb0f 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -2204,7 +2204,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { SemanticContextKind::None, expectedTypeContext); Builder.setAssociatedDecl(MD); - Builder.addBaseName(MD->getNameStr()); + auto moduleName = MD->getName(); + + // This checks if module aliasing was used. For example, when editing + // `import ...`, and `-module-alias Foo=Bar` was passed, we want to show + // Foo as an option to import, instead of Bar (name of the binary), as + // Foo is the name that should appear in source files. + auto aliasedName = Ctx.getRealModuleName(moduleName, ASTContext::ModuleAliasLookupOption::aliasFromRealName); + if (aliasedName != moduleName && // check if module aliasing was applied + !aliasedName.empty()) { // check an alias mapped to the binary name exists + moduleName = aliasedName; // if so, use the aliased name + } + Builder.addBaseName(moduleName.str()); Builder.addTypeAnnotation("Module"); if (R) Builder.setNotRecommended(*R); diff --git a/test/IDE/module-aliasing-code-complete.swift b/test/IDE/module-aliasing-code-complete.swift new file mode 100644 index 0000000000000..9d6fe4b867a5c --- /dev/null +++ b/test/IDE/module-aliasing-code-complete.swift @@ -0,0 +1,128 @@ +/// Test code completion with module aliasing +/// When -module-alias = is applied, code completion should show +/// the as that's the name which should appear in source files including import statements, +/// decls, expressions, etc. while getting visible decls come from the module of . +/// Below, XLogging is the alias and mapped to the real name AppleLogging. Note that the real name +/// AppleLogging should not appear in the code completion results. +/// +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-frontend %t/FileLogging.swift -module-name AppleLogging -module-alias XLogging=AppleLogging -emit-module -o %t/AppleLogging.swiftmodule + +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib1.swift -module-alias XLogging=AppleLogging -I %t > %t/result1.txt +// RUN: %FileCheck %s -check-prefix CHECK1 < %t/result1.txt + +// CHECK1-NOT: AppleLogging +// CHECK1: found code completion token MODULE_NAME at offset 43 +// CHECK1: Begin completions, 335 items +// CHECK1: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// CHECK1: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging +// CHECK1: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// CHECK1: End completions + + +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib2.swift -module-alias XLogging=AppleLogging -I %t > %t/result2.txt +// RUN: %FileCheck %s -check-prefix CHECK2 < %t/result2.txt + +// CHECK2-NOT: AppleLogging +// CHECK2: found code completion token MODULE_NAME at offset 48 +// CHECK2: Begin completions, 335 items +// CHECK2: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// CHECK2: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging +// CHECK2: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// CHECK2: End completions + + +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib3.swift -module-alias XLogging=AppleLogging -I %t > %t/result3.txt +// RUN: %FileCheck %s -check-prefix CHECK3 < %t/result3.txt + +// CHECK3-NOT: AppleLogging +// CHECK3: found code completion token MODULE_NAME at offset 49 +// CHECK3: Begin completions, 516 items +// CHECK3: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// CHECK3: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging +// CHECK3: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// CHECK3: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() +// CHECK3: End completions + + +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib4.swift -module-alias XLogging=AppleLogging -I %t > %t/result4.txt +// RUN: %FileCheck %s -check-prefix CHECK4 < %t/result4.txt + +// CHECK4-NOT: AppleLogging +// CHECK4: found code completion token MODULE_NAME at offset 58 +// CHECK4: Begin completions, 3 items +// CHECK4: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging +// CHECK4: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// CHECK4: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() +// CHECK4: End completions + +/// In the following, the module alias name should be shown as a module that can be imported instead of the real name +/// +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib5.swift -module-alias XLogging=AppleLogging -I %t > %t/result5.txt +// RUN: %FileCheck %s -check-prefix CHECK5 < %t/result5.txt + +/// In search paths, only AppleLogging.swiftmodule exists, but when `-module-alias XLogging=AppleLogging` is passed, +/// we want to only show XLogging as an option to import, not AppleLogging +// CHECK5-NOT: AppleLogging +// CHECK5: found code completion token MODULE_NAME at offset 7 +// CHECK5: Begin completions, 233 items +// CHECK5: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// CHECK5: End completions + + +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib5.swift -I %t > %t/result6.txt +// RUN: %FileCheck %s -check-prefix CHECK6 < %t/result6.txt + +/// In search paths, only AppleLogging.swiftmodule exists, and no module aliasing option is passed, so +/// just show AppleLogging as one of the modules that can be imported +// CHECK6-NOT: XLogging +// CHECK6: found code completion token MODULE_NAME at offset 7 +// CHECK6: Begin completions, 233 items +// CHECK6: Decl[Module]/None: AppleLogging[#Module#]; name=AppleLogging +// CHECK6: End completions + + +// BEGIN FileLogging.swift +public struct Logger { + public init() {} +} + +public protocol Logging { + var content: String { get } +} + +public func setupLogger() -> XLogging.Logger? { + return Logger() +} + +// BEGIN FileLib1.swift +import XLogging + +class ModuleNameInClause: #^MODULE_NAME^# { +} + +// BEGIN FileLib2.swift +import XLogging + +func testModuleNameInDecl() -> #^MODULE_NAME^# { +} + +// BEGIN FileLib3.swift +import XLogging + +func testModuleNameInBody() { + #^MODULE_NAME^# +} + +// BEGIN FileLib4.swift +import XLogging + +func testModuleNameInBody() { + XLogging.#^MODULE_NAME^# +} + +// BEGIN FileLib5.swift +import #^MODULE_NAME^# + diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index d288ed0e8740d..c11f7bf757a52 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -338,6 +338,10 @@ EnableCrossImportOverlays("enable-cross-import-overlays", llvm::cl::desc("Automatically import declared cross-import overlays."), llvm::cl::cat(Category), llvm::cl::init(false)); +static llvm::cl::list +ModuleAliases("module-alias", + llvm::cl::desc("Use '-module-alias =' to map a module of to a different name"), + llvm::cl::cat(Category)); static llvm::cl::opt SkipDeinit("skip-deinit", @@ -4233,6 +4237,10 @@ int main(int argc, char *argv[]) { InitInvok.getLangOptions().AllowModuleWithCompilerErrors = true; } + if (!options::ModuleAliases.empty()) { + InitInvok.setModuleAliasMap(options::ModuleAliases); + } + // Process the clang arguments last and allow them to override previously // set options. if (!CCArgs.empty()) { From 0ff41950668e47b40dccd9e709b6ef7e359544f9 Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Thu, 9 Dec 2021 19:22:20 -0800 Subject: [PATCH 2/7] Add repl code complete tests --- .../module-aliasing-batch-code-complete.swift | 68 +++++++++++++++++++ test/IDE/module-aliasing-code-complete.swift | 24 +++---- .../module-aliasing-repl-code-complete.swift | 46 +++++++++++++ 3 files changed, 126 insertions(+), 12 deletions(-) create mode 100644 test/IDE/module-aliasing-batch-code-complete.swift create mode 100644 test/IDE/module-aliasing-repl-code-complete.swift diff --git a/test/IDE/module-aliasing-batch-code-complete.swift b/test/IDE/module-aliasing-batch-code-complete.swift new file mode 100644 index 0000000000000..58f0fd80a8c51 --- /dev/null +++ b/test/IDE/module-aliasing-batch-code-complete.swift @@ -0,0 +1,68 @@ +/// Test code completion with module aliasing +/// When -module-alias = is applied, code completion should show +/// the as that's the name which should appear in source files including import statements, +/// decls, expressions, etc. while getting visible decls come from the module of . +/// Below, XLogging is the alias and mapped to the real name AppleLogging. Note that the real name +/// AppleLogging should not appear in the code completion results. +/// + + +// BEGIN FileLogging.swift +public struct Logger { + public init() {} +} + +public protocol Logging { + var content: String { get } +} + +public func setupLogger() -> XLogging.Logger? { + return Logger() +} + +// BEGIN FileLib1.swift +import XLogging + +class ModuleNameInClause: #^MODULE_NAME1^# { +} + +// BEGIN FileLib2.swift +import XLogging + +func testModuleNameInDecl() -> #^MODULE_NAME2^# { +} + +// BEGIN FileLib3.swift +import XLogging + +func test() { + let x = #^EXPR^# +} + +// BEGIN FileLib4.swift +import XLogging + +func testModuleNameInBody() { + XLogging.#^MODULE_NAME4^# +} + +// BEGIN FileLib5.swift +import #^MODULE_NAME5^# + + +// EXPR: Begin completion +// EXPR-NOT: AppleLogging +// EXPR-DAG: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// EXPR-DAG: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging +// EXPR-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// EXPR: End completions + + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %empty-directory(%t/modules) +// RUN: %target-swift-frontend %t/FileLogging.swift -module-name AppleLogging -module-alias XLogging=AppleLogging -emit-module -o %t/modules/AppleLogging.swiftmodule + +// RUN: %empty-directory(%t/output) +// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/FileLib3.swift -module-alias XLogging=AppleLogging -filecheck %raw-FileCheck -completion-output-dir %t/output -I %t/modules diff --git a/test/IDE/module-aliasing-code-complete.swift b/test/IDE/module-aliasing-code-complete.swift index 9d6fe4b867a5c..ac53878e0d537 100644 --- a/test/IDE/module-aliasing-code-complete.swift +++ b/test/IDE/module-aliasing-code-complete.swift @@ -14,8 +14,8 @@ // RUN: %FileCheck %s -check-prefix CHECK1 < %t/result1.txt // CHECK1-NOT: AppleLogging -// CHECK1: found code completion token MODULE_NAME at offset 43 -// CHECK1: Begin completions, 335 items +// CHECK1: found code completion token MODULE_NAME +// CHECK1: Begin completions // CHECK1: Decl[Module]/None: XLogging[#Module#]; name=XLogging // CHECK1: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging // CHECK1: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger @@ -26,8 +26,8 @@ // RUN: %FileCheck %s -check-prefix CHECK2 < %t/result2.txt // CHECK2-NOT: AppleLogging -// CHECK2: found code completion token MODULE_NAME at offset 48 -// CHECK2: Begin completions, 335 items +// CHECK2: found code completion token MODULE_NAME +// CHECK2: Begin completions // CHECK2: Decl[Module]/None: XLogging[#Module#]; name=XLogging // CHECK2: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging // CHECK2: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger @@ -38,8 +38,8 @@ // RUN: %FileCheck %s -check-prefix CHECK3 < %t/result3.txt // CHECK3-NOT: AppleLogging -// CHECK3: found code completion token MODULE_NAME at offset 49 -// CHECK3: Begin completions, 516 items +// CHECK3: found code completion token MODULE_NAME +// CHECK3: Begin completions // CHECK3: Decl[Module]/None: XLogging[#Module#]; name=XLogging // CHECK3: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging // CHECK3: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger @@ -51,8 +51,8 @@ // RUN: %FileCheck %s -check-prefix CHECK4 < %t/result4.txt // CHECK4-NOT: AppleLogging -// CHECK4: found code completion token MODULE_NAME at offset 58 -// CHECK4: Begin completions, 3 items +// CHECK4: found code completion token MODULE_NAME +// CHECK4: Begin completions // CHECK4: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging // CHECK4: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger // CHECK4: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() @@ -66,8 +66,8 @@ /// In search paths, only AppleLogging.swiftmodule exists, but when `-module-alias XLogging=AppleLogging` is passed, /// we want to only show XLogging as an option to import, not AppleLogging // CHECK5-NOT: AppleLogging -// CHECK5: found code completion token MODULE_NAME at offset 7 -// CHECK5: Begin completions, 233 items +// CHECK5: found code completion token MODULE_NAME +// CHECK5: Begin completions // CHECK5: Decl[Module]/None: XLogging[#Module#]; name=XLogging // CHECK5: End completions @@ -78,8 +78,8 @@ /// In search paths, only AppleLogging.swiftmodule exists, and no module aliasing option is passed, so /// just show AppleLogging as one of the modules that can be imported // CHECK6-NOT: XLogging -// CHECK6: found code completion token MODULE_NAME at offset 7 -// CHECK6: Begin completions, 233 items +// CHECK6: found code completion token MODULE_NAME +// CHECK6: Begin completions // CHECK6: Decl[Module]/None: AppleLogging[#Module#]; name=AppleLogging // CHECK6: End completions diff --git a/test/IDE/module-aliasing-repl-code-complete.swift b/test/IDE/module-aliasing-repl-code-complete.swift new file mode 100644 index 0000000000000..b416b3db17e70 --- /dev/null +++ b/test/IDE/module-aliasing-repl-code-complete.swift @@ -0,0 +1,46 @@ +/// Test REPL code completion with module aliasing +/// When -module-alias = is applied, code completion should show +/// the as that's the name which should appear in source files including import statements, +/// decls, expressions, etc. while getting visible decls come from the module of , which +/// is the name of the binary. +/// Below, XLogging is the alias and mapped to the real name AppleLogging. Note that the binary name +/// AppleLogging should not appear in the code completion results. +/// +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-frontend %t/FileLogging.swift -module-name AppleLogging -module-alias XLogging=AppleLogging -emit-module -o %t/AppleLogging.swiftmodule + +// RUN: %target-swift-ide-test -repl-code-completion -source-filename %t/FileLib1.swift -module-alias XLogging=AppleLogging -I %t > %t/result1.txt +// RUN: %FileCheck %s < %t/result1.txt + +// RUN: %target-swift-ide-test -repl-code-completion -source-filename %t/FileLib2.swift -module-alias XLogging=AppleLogging -I %t > %t/result2.txt +// RUN: %FileCheck %s < %t/result2.txt + +// CHECK: Begin completions +// CHECK-NOT: AppleLogging +// CHECK-DAG: XLogging +// CHECK: End completions + +// BEGIN FileLogging.swift +public struct Logger { + public init() {} +} + +public protocol Logging { + var content: String { get } +} + +public func setupLogger() -> XLogging.Logger? { + return Logger() +} + +// BEGIN FileLib1.swift +import + +// BEGIN FileLib2.swift +import XLogging +func f() { + X +} + From 1e5160b809127fa1c9ac698cfa2ccbc335a39d3b Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Fri, 10 Dec 2021 00:48:26 -0800 Subject: [PATCH 3/7] Update comments --- include/swift/Frontend/Frontend.h | 3 + lib/Frontend/CompilerInvocation.cpp | 3 - .../module-aliasing-batch-code-complete.swift | 68 ------------------- 3 files changed, 3 insertions(+), 71 deletions(-) delete mode 100644 test/IDE/module-aliasing-batch-code-complete.swift diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index d4650a291e1f5..3a8489cd3b671 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -309,6 +309,9 @@ class CompilerInvocation { return FrontendOpts.ModuleName; } + /// Sets module alias map with string args passed in via `-module-alias`. This assumes + /// the args are valid strings; full validation of input args for module aliasing is done at + /// \c ArgsToFrontendOptionsConverter::computeModulealiases. void setModuleAliasMap(std::vector args); std::string getOutputFilename() const { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b9d645400a450..7322a47d35d9a 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -262,9 +262,6 @@ void CompilerInvocation::setSDKPath(const std::string &Path) { updateRuntimeLibraryPaths(SearchPathOpts, LangOpts.Target); } -// This assumes the param args contains valid strings for module -// aliasing. The full validation of input for aliasing is done at -// ArgsToFrontendOptionsConverter::computeModulealiases. void CompilerInvocation::setModuleAliasMap(std::vector args) { // ModuleAliasMap should initially be empty as setting // it should be called only once diff --git a/test/IDE/module-aliasing-batch-code-complete.swift b/test/IDE/module-aliasing-batch-code-complete.swift deleted file mode 100644 index 58f0fd80a8c51..0000000000000 --- a/test/IDE/module-aliasing-batch-code-complete.swift +++ /dev/null @@ -1,68 +0,0 @@ -/// Test code completion with module aliasing -/// When -module-alias = is applied, code completion should show -/// the as that's the name which should appear in source files including import statements, -/// decls, expressions, etc. while getting visible decls come from the module of . -/// Below, XLogging is the alias and mapped to the real name AppleLogging. Note that the real name -/// AppleLogging should not appear in the code completion results. -/// - - -// BEGIN FileLogging.swift -public struct Logger { - public init() {} -} - -public protocol Logging { - var content: String { get } -} - -public func setupLogger() -> XLogging.Logger? { - return Logger() -} - -// BEGIN FileLib1.swift -import XLogging - -class ModuleNameInClause: #^MODULE_NAME1^# { -} - -// BEGIN FileLib2.swift -import XLogging - -func testModuleNameInDecl() -> #^MODULE_NAME2^# { -} - -// BEGIN FileLib3.swift -import XLogging - -func test() { - let x = #^EXPR^# -} - -// BEGIN FileLib4.swift -import XLogging - -func testModuleNameInBody() { - XLogging.#^MODULE_NAME4^# -} - -// BEGIN FileLib5.swift -import #^MODULE_NAME5^# - - -// EXPR: Begin completion -// EXPR-NOT: AppleLogging -// EXPR-DAG: Decl[Module]/None: XLogging[#Module#]; name=XLogging -// EXPR-DAG: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging -// EXPR-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger -// EXPR: End completions - - -// RUN: %empty-directory(%t) -// RUN: %{python} %utils/split_file.py -o %t %s - -// RUN: %empty-directory(%t/modules) -// RUN: %target-swift-frontend %t/FileLogging.swift -module-name AppleLogging -module-alias XLogging=AppleLogging -emit-module -o %t/modules/AppleLogging.swiftmodule - -// RUN: %empty-directory(%t/output) -// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/FileLib3.swift -module-alias XLogging=AppleLogging -filecheck %raw-FileCheck -completion-output-dir %t/output -I %t/modules From b5b285e54e8bb29d20145f1d45791dc3a3619883 Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Fri, 10 Dec 2021 16:06:11 -0800 Subject: [PATCH 4/7] Reuse compute module aliases function Update tests --- include/swift/Frontend/Frontend.h | 12 +- .../ArgsToFrontendOptionsConverter.cpp | 123 +++++++++--------- lib/Frontend/ArgsToFrontendOptionsConverter.h | 16 +++ lib/Frontend/CompilerInvocation.cpp | 25 +--- test/IDE/module-aliasing-code-complete.swift | 50 +++---- tools/swift-ide-test/swift-ide-test.cpp | 6 +- 6 files changed, 117 insertions(+), 115 deletions(-) diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 3a8489cd3b671..93d2a1b1f850e 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -309,10 +309,14 @@ class CompilerInvocation { return FrontendOpts.ModuleName; } - /// Sets module alias map with string args passed in via `-module-alias`. This assumes - /// the args are valid strings; full validation of input args for module aliasing is done at - /// \c ArgsToFrontendOptionsConverter::computeModulealiases. - void setModuleAliasMap(std::vector args); + /// Sets the module alias map with string args passed in via `-module-alias`. + /// \param args The arguments to `-module-alias`. If input has `-module-alias Foo=Bar + /// -module-alias Baz=Qux`, the args are ['Foo=Bar', 'Baz=Qux']. The name + /// Foo is the name that appears in source files, while it maps to Bar, the name + /// of the binary on disk, /path/to/Bar.swiftmodule(interface), under the hood. + /// \param diags Used to print diagnostics in case validation of the string args fails. + /// See \c ModuleAliasesConverter::computeModuleAliases on validation details. + void setModuleAliasMap(std::vector args, DiagnosticEngine &diags); std::string getOutputFilename() const { return FrontendOpts.InputsAndOutputs.getSingleOutputFilename(); diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 6b3a72542c7e3..4972904087953 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -253,8 +253,9 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.ModuleLinkName = A->getValue(); // This must be called after computing module name, module abi name, - // and module link name. - if (computeModuleAliases()) + // and module link name. If computing module aliases is unsuccessful, + // return early. + if (!computeModuleAliases()) return true; if (const Arg *A = Args.getLastArg(OPT_access_notes_path)) @@ -515,62 +516,7 @@ bool ArgsToFrontendOptionsConverter::setUpImmediateArgs() { bool ArgsToFrontendOptionsConverter::computeModuleAliases() { auto list = Args.getAllArgValues(options::OPT_module_alias); - if (!list.empty()) { - // ModuleAliasMap should initially be empty as setting - // it should be called only once - Opts.ModuleAliasMap.clear(); - - auto validate = [this](StringRef value, bool allowModuleName) -> bool - { - if (!allowModuleName) { - if (value == Opts.ModuleName || - value == Opts.ModuleABIName || - value == Opts.ModuleLinkName) { - Diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value); - return false; - } - } - if (value == STDLIB_NAME) { - Diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value); - return false; - } - if (!Lexer::isIdentifier(value)) { - Diags.diagnose(SourceLoc(), diag::error_bad_module_name, value, false); - return false; - } - return true; - }; - - for (auto item: list) { - auto str = StringRef(item); - // splits to an alias and the underlying name - auto pair = str.split('='); - auto lhs = pair.first; - auto rhs = pair.second; - - if (rhs.empty()) { // '=' is missing - Diags.diagnose(SourceLoc(), diag::error_module_alias_invalid_format, str); - return true; - } - if (!validate(lhs, false) || !validate(rhs, true)) { - return true; - } - - // First, add the underlying name as a key to prevent it from being - // used as an alias - if (!Opts.ModuleAliasMap.insert({rhs, StringRef()}).second) { - Diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, rhs); - return true; - } - // Next, add the alias as a key and the underlying name as a value to the map - auto underlyingName = Opts.ModuleAliasMap.find(rhs)->first(); - if (!Opts.ModuleAliasMap.insert({lhs, underlyingName}).second) { - Diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, lhs); - return true; - } - } - } - return false; + return ModuleAliasesConverter::computeModuleAliases(list, Opts, Diags); } bool ArgsToFrontendOptionsConverter::computeModuleName() { @@ -748,3 +694,64 @@ void ArgsToFrontendOptionsConverter::computeLLVMArgs() { Opts.LLVMArgs.push_back(A->getValue()); } } + +bool ModuleAliasesConverter::computeModuleAliases(std::vector args, + FrontendOptions &options, + DiagnosticEngine &diags) { + if (!args.empty()) { + // ModuleAliasMap should initially be empty as setting + // it should be called only once + options.ModuleAliasMap.clear(); + + auto validate = [&options, &diags](StringRef value, bool allowModuleName) -> bool + { + if (!allowModuleName) { + if (value == options.ModuleName || + value == options.ModuleABIName || + value == options.ModuleLinkName) { + diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value); + return false; + } + } + if (value == STDLIB_NAME) { + diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value); + return false; + } + if (!Lexer::isIdentifier(value)) { + diags.diagnose(SourceLoc(), diag::error_bad_module_name, value, false); + return false; + } + return true; + }; + + for (auto item: args) { + auto str = StringRef(item); + // splits to an alias and the underlying name + auto pair = str.split('='); + auto lhs = pair.first; + auto rhs = pair.second; + + if (rhs.empty()) { // '=' is missing + diags.diagnose(SourceLoc(), diag::error_module_alias_invalid_format, str); + return false; + } + if (!validate(lhs, false) || !validate(rhs, true)) { + return false; + } + + // First, add the underlying name as a key to prevent it from being + // used as an alias + if (!options.ModuleAliasMap.insert({rhs, StringRef()}).second) { + diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, rhs); + return false; + } + // Next, add the alias as a key and the underlying name as a value to the map + auto underlyingName = options.ModuleAliasMap.find(rhs)->first(); + if (!options.ModuleAliasMap.insert({lhs, underlyingName}).second) { + diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, lhs); + return false; + } + } + } + return true; +} diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.h b/lib/Frontend/ArgsToFrontendOptionsConverter.h index 31beb2cc74d54..83830c2c3d0c8 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.h +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.h @@ -73,6 +73,22 @@ class ArgsToFrontendOptionsConverter { determineRequestedAction(const llvm::opt::ArgList &); }; +class ModuleAliasesConverter { +public: + /// Sets the \c ModuleAliasMap in the \c FrontendOptions with args passed via `-module-alias`. + /// + /// \param args The arguments to `-module-alias`. If input has `-module-alias Foo=Bar + /// -module-alias Baz=Qux`, the args are ['Foo=Bar', 'Baz=Qux']. The name + /// Foo is the name that appears in source files, while it maps to Bar, the name + /// of the binary on disk, /path/to/Bar.swiftmodule(interface), under the hood. + /// \param options FrontendOptions containings the module alias map to set args to. + /// \param diags Used to print diagnostics in case validation of the args fails. + /// \return Whether the validation passed and successfully set the module alias map + static bool computeModuleAliases(std::vector args, + FrontendOptions &options, + DiagnosticEngine &diags); +}; + } // namespace swift #endif /* SWIFT_FRONTEND_ARGSTOFRONTENDOPTIONSCONVERTER_H */ diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7322a47d35d9a..e6af64b2f093b 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -262,28 +262,9 @@ void CompilerInvocation::setSDKPath(const std::string &Path) { updateRuntimeLibraryPaths(SearchPathOpts, LangOpts.Target); } -void CompilerInvocation::setModuleAliasMap(std::vector args) { - // ModuleAliasMap should initially be empty as setting - // it should be called only once - FrontendOpts.ModuleAliasMap.clear(); - for (auto item: args) { - auto str = StringRef(item); - // splits to an alias and the underlying name - auto pair = str.split('='); - auto lhs = pair.first; - auto rhs = pair.second; - if (rhs.empty()) // bad format, so skip to the next - continue; - if (!FrontendOpts.ModuleAliasMap.insert({rhs, StringRef()}).second) { - // the underlying name was already added, so skip - continue; - } - auto underlyingName = FrontendOpts.ModuleAliasMap.find(rhs)->first(); - if (!FrontendOpts.ModuleAliasMap.insert({lhs, underlyingName}).second) { - // the alias was already added, so skip - continue; - } - } +void CompilerInvocation::setModuleAliasMap(std::vector args, + DiagnosticEngine &diags) { + ModuleAliasesConverter::computeModuleAliases(args, FrontendOpts, diags); } static bool ParseFrontendArgs( diff --git a/test/IDE/module-aliasing-code-complete.swift b/test/IDE/module-aliasing-code-complete.swift index ac53878e0d537..db90925dd4241 100644 --- a/test/IDE/module-aliasing-code-complete.swift +++ b/test/IDE/module-aliasing-code-complete.swift @@ -11,51 +11,41 @@ // RUN: %target-swift-frontend %t/FileLogging.swift -module-name AppleLogging -module-alias XLogging=AppleLogging -emit-module -o %t/AppleLogging.swiftmodule // RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib1.swift -module-alias XLogging=AppleLogging -I %t > %t/result1.txt -// RUN: %FileCheck %s -check-prefix CHECK1 < %t/result1.txt - -// CHECK1-NOT: AppleLogging -// CHECK1: found code completion token MODULE_NAME -// CHECK1: Begin completions -// CHECK1: Decl[Module]/None: XLogging[#Module#]; name=XLogging -// CHECK1: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging -// CHECK1: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger -// CHECK1: End completions - +// RUN: %FileCheck %s -check-prefix CHECK12 < %t/result1.txt // RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib2.swift -module-alias XLogging=AppleLogging -I %t > %t/result2.txt -// RUN: %FileCheck %s -check-prefix CHECK2 < %t/result2.txt - -// CHECK2-NOT: AppleLogging -// CHECK2: found code completion token MODULE_NAME -// CHECK2: Begin completions -// CHECK2: Decl[Module]/None: XLogging[#Module#]; name=XLogging -// CHECK2: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging -// CHECK2: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger -// CHECK2: End completions +// RUN: %FileCheck %s -check-prefix CHECK12 < %t/result2.txt +// CHECK12: found code completion token MODULE_NAME +// CHECK12: Begin completions +// CHECK12-NOT: AppleLogging +// CHECK12-DAG: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// CHECK12-DAG: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging +// CHECK12-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// CHECK12: End completions // RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib3.swift -module-alias XLogging=AppleLogging -I %t > %t/result3.txt // RUN: %FileCheck %s -check-prefix CHECK3 < %t/result3.txt -// CHECK3-NOT: AppleLogging // CHECK3: found code completion token MODULE_NAME // CHECK3: Begin completions -// CHECK3: Decl[Module]/None: XLogging[#Module#]; name=XLogging -// CHECK3: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging -// CHECK3: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger -// CHECK3: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() +// CHECK3-NOT: AppleLogging +// CHECK3-DAG: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// CHECK3-DAG: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging +// CHECK3-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// CHECK3-DAG: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() // CHECK3: End completions // RUN: %target-swift-ide-test -code-completion -code-completion-token=MODULE_NAME -source-filename %t/FileLib4.swift -module-alias XLogging=AppleLogging -I %t > %t/result4.txt // RUN: %FileCheck %s -check-prefix CHECK4 < %t/result4.txt -// CHECK4-NOT: AppleLogging // CHECK4: found code completion token MODULE_NAME // CHECK4: Begin completions -// CHECK4: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging -// CHECK4: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger -// CHECK4: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() +// CHECK4-NOT: AppleLogging +// CHECK4-DAG: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging +// CHECK4-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// CHECK4-DAG: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() // CHECK4: End completions /// In the following, the module alias name should be shown as a module that can be imported instead of the real name @@ -65,9 +55,9 @@ /// In search paths, only AppleLogging.swiftmodule exists, but when `-module-alias XLogging=AppleLogging` is passed, /// we want to only show XLogging as an option to import, not AppleLogging -// CHECK5-NOT: AppleLogging // CHECK5: found code completion token MODULE_NAME // CHECK5: Begin completions +// CHECK5-NOT: AppleLogging // CHECK5: Decl[Module]/None: XLogging[#Module#]; name=XLogging // CHECK5: End completions @@ -77,9 +67,9 @@ /// In search paths, only AppleLogging.swiftmodule exists, and no module aliasing option is passed, so /// just show AppleLogging as one of the modules that can be imported -// CHECK6-NOT: XLogging // CHECK6: found code completion token MODULE_NAME // CHECK6: Begin completions +// CHECK6-NOT: XLogging // CHECK6: Decl[Module]/None: AppleLogging[#Module#]; name=AppleLogging // CHECK6: End completions diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index c11f7bf757a52..367469ff704e2 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -4238,7 +4238,11 @@ int main(int argc, char *argv[]) { } if (!options::ModuleAliases.empty()) { - InitInvok.setModuleAliasMap(options::ModuleAliases); + PrintingDiagnosticConsumer PDC; + SourceManager SM; + DiagnosticEngine Diags(SM); + Diags.addConsumer(PDC); + InitInvok.setModuleAliasMap(options::ModuleAliases, Diags); } // Process the clang arguments last and allow them to override previously From 541c0787952fba202e8d37d433d2bab9046d8d69 Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Fri, 10 Dec 2021 16:12:10 -0800 Subject: [PATCH 5/7] Update input description --- tools/swift-ide-test/swift-ide-test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 367469ff704e2..e1047f3cf261d 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -340,7 +340,7 @@ EnableCrossImportOverlays("enable-cross-import-overlays", llvm::cl::init(false)); static llvm::cl::list ModuleAliases("module-alias", - llvm::cl::desc("Use '-module-alias =' to map a module of to a different name"), + llvm::cl::desc("Use '-module-alias =' to map a module of that appears in source code to "), llvm::cl::cat(Category)); static llvm::cl::opt From 0fc4fe2e67b69e33ad5725cc4d0e4befffbf01d3 Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Fri, 10 Dec 2021 16:55:27 -0800 Subject: [PATCH 6/7] Add batch-code-complete test --- .../module-aliasing-batch-code-complete.swift | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 test/IDE/module-aliasing-batch-code-complete.swift diff --git a/test/IDE/module-aliasing-batch-code-complete.swift b/test/IDE/module-aliasing-batch-code-complete.swift new file mode 100644 index 0000000000000..3b807a7adbb6c --- /dev/null +++ b/test/IDE/module-aliasing-batch-code-complete.swift @@ -0,0 +1,80 @@ +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %empty-directory(%t/Modules) +// RUN: %target-swift-frontend -emit-module -module-name AppleLogging -module-alias XLogging=AppleLogging -o %t/Modules %t/FileLogging.swift + +// BEGIN FileLogging.swift +public struct Logger { + public init() {} +} + +public protocol Logging { + var name: String { get } +} + +public func setupLogger() -> XLogging.Logger? { + return Logger() +} + +// RUN: %empty-directory(%t/Out) +// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/FileLib1.swift -module-alias XLogging=AppleLogging -filecheck %raw-FileCheck -completion-output-dir %t/Out -I %t/Modules + +// BEGIN FileLib1.swift +import XLogging + +func testModuleNameInBody() { + #^EXPR^# +} + +// EXPR: Begin completion +// EXPR-NOT: AppleLogging +// EXPR-DAG: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// EXPR-DAG: Decl[Protocol]/OtherModule[XLogging]/Flair[RareType]: Logging[#Logging#]; name=Logging +// EXPR-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// EXPR-DAG: Decl[FreeFunction]/OtherModule[XLogging]: setupLogger()[#Logger?#]; name=setupLogger() +// EXPR: End completions + +// RUN: %empty-directory(%t/Out) +// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/FileLib2.swift -module-alias XLogging=AppleLogging -filecheck %raw-FileCheck -completion-output-dir %t/Out -I %t/Modules + +// BEGIN FileLib2.swift +import XLogging + +class ModuleNameInClause: #^MODULE^# { +} + +// MODULE: Begin completion +// MODULE-NOT: AppleLogging +// MODULE-DAG: Decl[Module]/None: XLogging[#Module#]; name=XLogging + +// MODULE-DAG: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging +// MODULE-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// MODULE: End completions + +// RUN: %empty-directory(%t/Out) +// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/FileLib3.swift -module-alias XLogging=AppleLogging -filecheck %raw-FileCheck -completion-output-dir %t/Out -I %t/Modules + +// BEGIN FileLib3.swift +import XLogging + +func testModuleNameInDecl() -> #^TYPE^# { +} + +// TYPE: Begin completion +// TYPE-NOT: AppleLogging +// TYPE-DAG: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// TYPE-DAG: Decl[Protocol]/OtherModule[XLogging]: Logging[#Logging#]; name=Logging +// TYPE-DAG: Decl[Struct]/OtherModule[XLogging]: Logger[#Logger#]; name=Logger +// TYPE: End completions + +// RUN: %empty-directory(%t/Out) +// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/FileLib4.swift -module-alias XLogging=AppleLogging -filecheck %raw-FileCheck -completion-output-dir %t/Out -I %t/Modules + +// BEGIN FileLib4.swift +import #^IMPORT^# + +// IMPORT: Begin completion +// IMPORT-NOT: AppleLogging +// IMPORT: Decl[Module]/None: XLogging[#Module#]; name=XLogging +// IMPORT: End completions From 4ad3a551b44c1582d0401c011193d53244875db2 Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Fri, 10 Dec 2021 17:14:16 -0800 Subject: [PATCH 7/7] Exit early args are invalid Add batch-code-compelte test --- include/swift/Frontend/Frontend.h | 3 ++- lib/Frontend/CompilerInvocation.cpp | 4 ++-- test/IDE/module-aliasing-repl-code-complete.swift | 2 +- tools/swift-ide-test/swift-ide-test.cpp | 5 ++++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 93d2a1b1f850e..947ac5c505a73 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -316,7 +316,8 @@ class CompilerInvocation { /// of the binary on disk, /path/to/Bar.swiftmodule(interface), under the hood. /// \param diags Used to print diagnostics in case validation of the string args fails. /// See \c ModuleAliasesConverter::computeModuleAliases on validation details. - void setModuleAliasMap(std::vector args, DiagnosticEngine &diags); + /// \return Whether setting module alias map succeeded; false if args validation fails. + bool setModuleAliasMap(std::vector args, DiagnosticEngine &diags); std::string getOutputFilename() const { return FrontendOpts.InputsAndOutputs.getSingleOutputFilename(); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index e6af64b2f093b..ec6aeb5c84078 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -262,9 +262,9 @@ void CompilerInvocation::setSDKPath(const std::string &Path) { updateRuntimeLibraryPaths(SearchPathOpts, LangOpts.Target); } -void CompilerInvocation::setModuleAliasMap(std::vector args, +bool CompilerInvocation::setModuleAliasMap(std::vector args, DiagnosticEngine &diags) { - ModuleAliasesConverter::computeModuleAliases(args, FrontendOpts, diags); + return ModuleAliasesConverter::computeModuleAliases(args, FrontendOpts, diags); } static bool ParseFrontendArgs( diff --git a/test/IDE/module-aliasing-repl-code-complete.swift b/test/IDE/module-aliasing-repl-code-complete.swift index b416b3db17e70..215fc67e48f42 100644 --- a/test/IDE/module-aliasing-repl-code-complete.swift +++ b/test/IDE/module-aliasing-repl-code-complete.swift @@ -19,7 +19,7 @@ // CHECK: Begin completions // CHECK-NOT: AppleLogging -// CHECK-DAG: XLogging +// CHECK: XLogging // CHECK: End completions // BEGIN FileLogging.swift diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index e1047f3cf261d..b532f905cc298 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -4242,7 +4242,10 @@ int main(int argc, char *argv[]) { SourceManager SM; DiagnosticEngine Diags(SM); Diags.addConsumer(PDC); - InitInvok.setModuleAliasMap(options::ModuleAliases, Diags); + if (!InitInvok.setModuleAliasMap(options::ModuleAliases, Diags)) { + llvm::errs() << "invalid module alias arguments\n"; + return 1; + } } // Process the clang arguments last and allow them to override previously