diff --git a/lib/Frontend/ParseableInterfaceSupport.cpp b/lib/Frontend/ParseableInterfaceSupport.cpp index 9320ae9f61168..800354c1a4b97 100644 --- a/lib/Frontend/ParseableInterfaceSupport.cpp +++ b/lib/Frontend/ParseableInterfaceSupport.cpp @@ -28,6 +28,7 @@ #include "clang/Basic/Module.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringSet.h" @@ -169,6 +170,16 @@ createInvocationForBuildingFromInterface(ASTContext &Ctx, StringRef ModuleName, SubInvocation.setClangModuleCachePath(CacheDir); SubInvocation.getFrontendOptions().PrebuiltModuleCachePath = PrebuiltCacheDir; + // Respect the detailed-record preprocessor setting of the parent context. + // This, and the "raw" clang module format it implicitly enables, are required + // by sourcekitd. + if (auto *ClangLoader = Ctx.getClangModuleLoader()) { + auto &Opts = ClangLoader->getClangInstance().getPreprocessorOpts(); + if (Opts.DetailedRecord) { + SubInvocation.getClangImporterOptions().DetailedPreprocessingRecord = true; + } + } + // Inhibit warnings from the SubInvocation since we are assuming the user // is not in a position to fix them. SubInvocation.getDiagnosticOptions().SuppressWarnings = true; @@ -452,7 +463,7 @@ bool ParseableInterfaceModuleLoader::buildSwiftModuleFromSwiftInterface( return; } - SubError = Diags.hadAnyError(); + SubError = SubInstance.getDiags().hadAnyError(); }); return !RunSuccess || SubError; } diff --git a/test/ParseableInterface/ModuleCache/module-cache-errors-in-importing-file.swift b/test/ParseableInterface/ModuleCache/module-cache-errors-in-importing-file.swift new file mode 100644 index 0000000000000..2aa7c3c20ce84 --- /dev/null +++ b/test/ParseableInterface/ModuleCache/module-cache-errors-in-importing-file.swift @@ -0,0 +1,23 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/modulecache) +// +// Setup builds a parseable interface for a module SomeModule (built from some-module.swift). +// This test checks we still build and load its corresponding .swiftmodule when the file that imports it contains an error prior to the import statement. + +// Setup phase 1: Write the input file. +// +// RUN: echo 'public func SomeFunc() -> Int { return 42; }' >>%t/some-module.swift + +// Setup phase 2: build the module. +// +// RUN: %target-swift-frontend -I %t -emit-parseable-module-interface-path %t/SomeModule.swiftinterface -module-name SomeModule %t/some-module.swift -emit-module -o /dev/null + +// Actual test: compile and verify the import succeeds (i.e. we only report the error in this file) +// +// RUN: %target-swift-frontend -typecheck -verify -I %t -module-cache-path %t/modulecache -enable-parseable-module-interface %s + +unresolved // expected-error {{use of unresolved identifier 'unresolved'}} + +import SomeModule + +print(SomeFunc()) diff --git a/test/SourceKit/CodeComplete/Inputs/parseable-interface/MyPoint.swift b/test/SourceKit/CodeComplete/Inputs/parseable-interface/MyPoint.swift new file mode 100644 index 0000000000000..707c85f8aa30d --- /dev/null +++ b/test/SourceKit/CodeComplete/Inputs/parseable-interface/MyPoint.swift @@ -0,0 +1,13 @@ +public struct MyPoint { + public let x: Double + public let y: Double + + public init(x: Double, y: Double) { + self.x = x + self.y = y + } + + public var magnitudeSquared: Double { + return x*x + y*y + } +} diff --git a/test/SourceKit/CodeComplete/Inputs/parseable-interface/MyPointExtensions.swift b/test/SourceKit/CodeComplete/Inputs/parseable-interface/MyPointExtensions.swift new file mode 100644 index 0000000000000..37dfbabc2c165 --- /dev/null +++ b/test/SourceKit/CodeComplete/Inputs/parseable-interface/MyPointExtensions.swift @@ -0,0 +1,7 @@ +import MyPoint + +public extension MyPoint { + var magnitude: Double { + return magnitudeSquared.squareRoot() + } +} diff --git a/test/SourceKit/CodeComplete/complete_swiftinterface.swift b/test/SourceKit/CodeComplete/complete_swiftinterface.swift new file mode 100644 index 0000000000000..26d96428076ec --- /dev/null +++ b/test/SourceKit/CodeComplete/complete_swiftinterface.swift @@ -0,0 +1,28 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/modulecache) + +// 1) Build .swiftinterface files for MyPoint and MyExtensions, using a non-default module cache path +// RUN: %target-swift-frontend -emit-parseable-module-interface-path %t/MyPoint.swiftinterface -module-name MyPoint -emit-module -o /dev/null %S/Inputs/parseable-interface/MyPoint.swift +// RUN: %target-swift-frontend -emit-parseable-module-interface-path %t/MyPointExtensions.swiftinterface -module-name MyPointExtensions -emit-module -o /dev/null -enable-parseable-module-interface -module-cache-path %t/modulecache -I %t %S/Inputs/parseable-interface/MyPointExtensions.swift +// RUN: %empty-directory(%t/modulecache) + +// 2) Check completion using the default (cold) module cache +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MEMBER -source-filename %s -I %t | %FileCheck %s + +// 3) Check completion again with a warm module cache +// RUN: %target-swift-ide-test -code-completion -code-completion-token=MEMBER -source-filename %s -I %t | %FileCheck %s + +import MyPoint +import MyPointExtensions + +let x = MyPoint(x: 1, y: 10.5) + +print(x.#^MEMBER^#) + +// CHECK: Begin completions, 5 items +// CHECK: Keyword[self]/CurrNominal: self[#MyPoint#]; name=self +// CHECK: Decl[InstanceVar]/CurrNominal: x[#Double#]; name=x +// CHECK: Decl[InstanceVar]/CurrNominal: y[#Double#]; name=y +// CHECK: Decl[InstanceVar]/CurrNominal: magnitudeSquared[#Double#]; name=magnitudeSquared +// CHECK: Decl[InstanceVar]/CurrNominal: magnitude[#Double#]; name=magnitude +// CHECK: End completions diff --git a/test/SourceKit/InterfaceGen/gen_swift_module.swift b/test/SourceKit/InterfaceGen/gen_swift_module.swift index ad2ff5e73e8bd..0df2feec4c41c 100644 --- a/test/SourceKit/InterfaceGen/gen_swift_module.swift +++ b/test/SourceKit/InterfaceGen/gen_swift_module.swift @@ -24,3 +24,11 @@ func f(s : inout [Int]) { // RUN: %sourcekitd-test -req=interface-gen-open -module Swift \ // RUN: == -req=find-usr -usr "s:SMsSkRzSL7ElementSTRpzrlE4sortyyF::SYNTHESIZED::s:Sa::SYNTHESIZED::USRDOESNOTEXIST" | %FileCheck -check-prefix=SYNTHESIZED-USR3 %s // SYNTHESIZED-USR3-NOT: USR NOT FOUND + + +// Test we can generate the interface of a module loaded via a .swiftinterface file correctly + +// RUN: %empty-directory(%t.mod) +// RUN: %swift -emit-module -o /dev/null -emit-parseable-module-interface-path %t.mod/swift_mod.swiftinterface %S/Inputs/swift_mod.swift -parse-as-library +// RUN: %sourcekitd-test -req=interface-gen -module swift_mod -- -I %t.mod -enable-parseable-module-interface -module-cache-path %t/mcp > %t.response +// RUN: diff -u %s.from_swiftinterface.response %t.response diff --git a/test/SourceKit/InterfaceGen/gen_swift_module.swift.from_swiftinterface.response b/test/SourceKit/InterfaceGen/gen_swift_module.swift.from_swiftinterface.response new file mode 100644 index 0000000000000..17ecf89b865ff --- /dev/null +++ b/test/SourceKit/InterfaceGen/gen_swift_module.swift.from_swiftinterface.response @@ -0,0 +1,112 @@ + +public class MyClass { + + public func pub_method() +} + +public func pub_function() + + +[ + { + key.kind: source.lang.swift.syntaxtype.attribute.builtin, + key.offset: 1, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 8, + key.length: 5 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 14, + key.length: 7 + }, + { + key.kind: source.lang.swift.syntaxtype.attribute.builtin, + key.offset: 29, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 36, + key.length: 4 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 41, + key.length: 10 + }, + { + key.kind: source.lang.swift.syntaxtype.attribute.builtin, + key.offset: 57, + key.length: 6 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 64, + key.length: 4 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 69, + key.length: 12 + } +] +<> +[ + { + key.kind: source.lang.swift.decl.class, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "MyClass", + key.offset: 8, + key.length: 47, + key.runtime_name: "_TtC4main7MyClass", + key.nameoffset: 14, + key.namelength: 7, + key.bodyoffset: 23, + key.bodylength: 31, + key.attributes: [ + { + key.offset: 1, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "pub_method()", + key.offset: 36, + key.length: 17, + key.nameoffset: 41, + key.namelength: 12, + key.attributes: [ + { + key.offset: 29, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.function.free, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "pub_function()", + key.offset: 64, + key.length: 19, + key.nameoffset: 69, + key.namelength: 14, + key.attributes: [ + { + key.offset: 57, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ] + } +] diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp index 72ee213c4709c..4b7a73521554a 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp @@ -708,6 +708,7 @@ void SwiftLangSupport::editorOpenInterface(EditorConsumer &Consumer, } Invocation.getClangImporterOptions().ImportForwardDeclarations = true; + Invocation.getFrontendOptions().EnableParseableModuleInterface = true; std::string ErrMsg; auto IFaceGenRef = SwiftInterfaceGenContext::create(Name, diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index e0f4b37f7313e..94c9d09a6bc52 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -268,6 +268,12 @@ static llvm::cl::opt ModuleCachePath("module-cache-path", llvm::cl::desc("Clang module cache path"), llvm::cl::cat(Category)); +static llvm::cl::opt +EnableParseableModuleInterface("enable-parseable-module-interface", + llvm::cl::desc("Enable loading .swiftinterface files when available"), + llvm::cl::cat(Category), + llvm::cl::init(true)); + static llvm::cl::opt PCHOutputDir("pch-output-dir", llvm::cl::desc("place autogenerated PCH files in this directory"), @@ -3256,6 +3262,8 @@ int main(int argc, char *argv[]) { InitInvok.getLangOptions().EffectiveLanguageVersion = actual.getValue(); } } + InitInvok.getFrontendOptions().EnableParseableModuleInterface = + options::EnableParseableModuleInterface; InitInvok.getClangImporterOptions().ModuleCachePath = options::ModuleCachePath; InitInvok.getClangImporterOptions().PrecompiledHeaderOutputDir =