Merge pull request #10729 from itaiferber/4.0-non-optional-coding-paths
[4.0] Make coding paths non-optional [DO NOT MERGE]
diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def
index 975053d..e098c22 100644
--- a/include/swift/AST/DiagnosticsFrontend.def
+++ b/include/swift/AST/DiagnosticsFrontend.def
@@ -167,6 +167,17 @@
ERROR(error_parse_input_file,none,
"error parsing input file '%0' (%1)", (StringRef, StringRef))
+ERROR(error_write_index_unit,none,
+ "writing index unit file: %0", (StringRef))
+ERROR(error_create_index_dir,none,
+ "creating index directory: %0", (StringRef))
+ERROR(error_write_index_record,none,
+ "writing index record file: %0", (StringRef))
+ERROR(error_index_failed_status_check,none,
+ "failed file status check: %0", (StringRef))
+ERROR(error_index_inputs_more_than_outputs,none,
+ "index output filenames do not match input source files", ())
+
ERROR(error_formatting_multiple_file_ranges,none,
"file ranges don't support multiple input files", ())
@@ -183,6 +194,14 @@
"symbol '%0' (%1) is in generated IR file, but not in TBD file",
(StringRef, StringRef))
+ERROR(invalid_conditional_compilation_flag,none,
+ "conditional compilation flags must be valid Swift identifiers (rather than '%0')",
+ (StringRef))
+
+WARNING(cannot_assign_value_to_conditional_compilation_flag,none,
+ "conditional compilation flags do not have values in Swift; they are "
+ "either present or absent (rather than '%0')", (StringRef))
+
#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG
diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h
index c422d7d..44d0f18 100644
--- a/include/swift/AST/ProtocolConformance.h
+++ b/include/swift/AST/ProtocolConformance.h
@@ -462,6 +462,8 @@
/// protocol, which line up with the conformance constraints in the
/// protocol's requirement signature.
ArrayRef<ProtocolConformanceRef> getSignatureConformances() const {
+ if (Resolver)
+ resolveLazyInfo();
return SignatureConformances;
}
diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h
index 9704256..b3da68c 100644
--- a/include/swift/ClangImporter/ClangImporterOptions.h
+++ b/include/swift/ClangImporter/ClangImporterOptions.h
@@ -37,6 +37,9 @@
/// Equivalent to Clang's -mcpu=.
std::string TargetCPU;
+ /// The path to which we should store indexing data, if any.
+ std::string IndexStorePath;
+
/// The bridging header or PCH that will be imported.
std::string BridgingHeader;
diff --git a/include/swift/Driver/Types.def b/include/swift/Driver/Types.def
index 0306909..98cb9b3 100644
--- a/include/swift/Driver/Types.def
+++ b/include/swift/Driver/Types.def
@@ -61,6 +61,10 @@
TYPE("tbd", TBD, "tbd", "")
TYPE("module-trace", ModuleTrace, "trace.json", "")
+// BEGIN APPLE-ONLY OUTPUT TYPES
+TYPE("index-data", IndexData, "", "")
+// END APPLE-ONLY OUTPUT TYPES
+
// Misc types
TYPE("pcm", ClangModuleFile, "pcm", "")
TYPE("pch", PCH, "pch", "")
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 021e27b..92ce827 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -132,6 +132,12 @@
/// The path to collect the group information for the compiled source files.
std::string GroupInfoPath;
+ /// The path to which we should store indexing data, if any.
+ std::string IndexStorePath;
+
+ /// Emit index data for imported serialized swift system modules.
+ bool IndexSystemModules = false;
+
/// If non-zero, warn when a function body takes longer than this many
/// milliseconds to type-check.
///
diff --git a/include/swift/Index/IndexRecord.h b/include/swift/Index/IndexRecord.h
new file mode 100644
index 0000000..8ddcb44
--- /dev/null
+++ b/include/swift/Index/IndexRecord.h
@@ -0,0 +1,83 @@
+//===--- IndexRecord.h - Entry point for recording index data ---*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_INDEX_INDEXRECORD_H
+#define SWIFT_INDEX_INDEXRECORD_H
+
+#include "swift/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace swift {
+class DependencyTracker;
+class ModuleDecl;
+class SourceFile;
+
+namespace index {
+
+/// Index the given source file and store the results to \p indexStorePath.
+///
+/// \param primarySourceFile The source file to index.
+///
+/// \param indexUnitToken A unique identifier for this translation unit in the
+/// form of a file path.
+///
+/// \param indexStorePath The location to write the indexing data to.
+///
+/// \param indexSystemModules If true, emit index data for imported serialized
+/// swift system modules.
+///
+/// \param isDebugCompilation true for non-optimized compiler invocation.
+///
+/// \param targetTriple The target for this compilation.
+///
+/// \param dependencyTracker The set of dependencies seen while building.
+bool indexAndRecord(SourceFile *primarySourceFile, StringRef indexUnitToken,
+ StringRef indexStorePath, bool indexSystemModules,
+ bool isDebugCompilation, StringRef targetTriple,
+ const DependencyTracker &dependencyTracker);
+
+/// Index the given module and store the results to \p indexStorePath.
+///
+/// \param module The module to index.
+///
+/// \param indexUnitTokens A list of unique identifiers for the index units to
+/// be written. This may either be one unit per source file of \p module, or it
+/// may be a single unit, in which case all the index information will be
+/// combined into a single unit.
+///
+/// \param moduleUnitToken A unique identifier for this module unit in the form
+/// of a file path. Only used if \p indexUnitTokens are specified for each
+/// source file, otherwise the single \p indexUnitTokens value is used instead.
+///
+/// \param indexStorePath The location to write the indexing data to.
+///
+/// \param indexSystemModules If true, emit index data for imported serialized
+/// swift system modules.
+///
+/// \param isDebugCompilation true for non-optimized compiler invocation.
+///
+/// \param targetTriple The target for this compilation.
+///
+/// \param dependencyTracker The set of dependencies seen while building.
+bool indexAndRecord(ModuleDecl *module, ArrayRef<std::string> indexUnitTokens,
+ StringRef moduleUnitToken, StringRef indexStorePath,
+ bool indexSystemModules, bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker);
+// FIXME: indexUnitTokens could be StringRef, but that creates an impedance
+// mismatch in the caller.
+
+} // end namespace index
+} // end namespace swift
+
+#endif // SWIFT_INDEX_INDEXRECORD_H
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 4bc4968..d814367 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -414,6 +414,9 @@
HelpText<"Use the pass pipeline defined by <pass_pipeline_file>">,
MetaVarName<"<pass_pipeline_file>">;
+def index_system_modules : Flag<["-"], "index-system-modules">,
+ HelpText<"Emit index data for imported serialized swift system modules">;
+
def dump_interface_hash : Flag<["-"], "dump-interface-hash">,
HelpText<"Parse input file(s) and dump interface token hash(es)">,
ModeOpt;
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index 73b9261..2bdbe29 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -646,6 +646,18 @@
HelpText<"Specify the type of coverage instrumentation for Sanitizers and"
" additional options separated by commas">;
+def index_file : Flag<["-"], "index-file">,
+ HelpText<"Produce index data for a source file">, ModeOpt,
+ Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
+def index_file_path : Separate<["-"], "index-file-path">,
+ Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ HelpText<"Produce index data for file <path>">,
+ MetaVarName<"<path>">;
+
+def index_store_path : Separate<["-"], "index-store-path">,
+ Flags<[FrontendOption]>, MetaVarName<"<path>">,
+ HelpText<"Store indexing data to <path>">;
+
def enforce_exclusivity_EQ : Joined<["-"], "enforce-exclusivity=">,
Flags<[FrontendOption]>, MetaVarName<"<enforcement>">,
HelpText<"Enforce law of exclusivity">;
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index d10e77e..e61924c 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -46,6 +46,7 @@
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Index/IndexingAction.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/Preprocessor.h"
@@ -705,6 +706,11 @@
invocationArgStrs.push_back(overrideResourceDir);
}
+ if (!importerOpts.IndexStorePath.empty()) {
+ invocationArgStrs.push_back("-index-store-path");
+ invocationArgStrs.push_back(importerOpts.IndexStorePath);
+ }
+
for (auto extraArg : importerOpts.ExtraArgs) {
invocationArgStrs.push_back(extraArg);
}
@@ -1306,6 +1312,7 @@
invocation->getFrontendOpts().Inputs.push_back(
clang::FrontendInputFile(headerPath, clang::IK_ObjC));
invocation->getFrontendOpts().OutputFile = outputPCHPath;
+ invocation->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH;
invocation->getPreprocessorOpts().resetNonModularOptions();
clang::CompilerInstance emitInstance(
@@ -1319,8 +1326,15 @@
emitInstance.createSourceManager(fileManager);
emitInstance.setTarget(&Impl.Instance->getTarget());
- clang::GeneratePCHAction action;
- emitInstance.ExecuteAction(action);
+ std::unique_ptr<clang::FrontendAction> action;
+ action.reset(new clang::GeneratePCHAction());
+ if (!emitInstance.getFrontendOpts().IndexStorePath.empty()) {
+ action = clang::index::
+ createIndexDataRecordingAction(emitInstance.getFrontendOpts(),
+ std::move(action));
+ }
+ emitInstance.ExecuteAction(*action);
+
if (emitInstance.getDiagnostics().hasErrorOccurred()) {
Impl.SwiftContext.Diags.diagnose({},
diag::bridging_header_pch_error,
@@ -1407,6 +1421,17 @@
auto importRAII = diagClient.handleImport(clangPath.front().first,
importLoc);
+ std::string preservedIndexStorePathOption;
+ auto &clangFEOpts = Impl.Instance->getFrontendOpts();
+ if (!clangFEOpts.IndexStorePath.empty()) {
+ StringRef moduleName = path[0].first->getName();
+ // Ignore the SwiftShims module for the index data.
+ if (moduleName == Impl.SwiftContext.SwiftShimsModuleName.str()) {
+ preservedIndexStorePathOption = clangFEOpts.IndexStorePath;
+ clangFEOpts.IndexStorePath.clear();
+ }
+ }
+
// FIXME: The source location here is completely bogus. It can't be
// invalid, it can't be the same thing twice in a row, and it has to come
// from an actual buffer, so we make a fake buffer and just use a counter.
@@ -1427,6 +1452,12 @@
clang::ModuleLoadResult result =
Impl.Instance->loadModule(clangImportLoc, path, visibility,
/*IsInclusionDirective=*/false);
+
+ if (!preservedIndexStorePathOption.empty()) {
+ // Restore the -index-store-path option.
+ clangFEOpts.IndexStorePath = preservedIndexStorePathOption;
+ }
+
if (result && makeVisible)
Impl.getClangPreprocessor().makeModuleVisible(result, clangImportLoc);
return result;
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 93c92fa..7d6a172 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -6348,7 +6348,8 @@
auto conformance = ctx.getConformance(dc->getDeclaredTypeInContext(),
protocols[i], SourceLoc(), dc,
ProtocolConformanceState::Incomplete);
- Impl.scheduleFinishProtocolConformance(conformance);
+ conformance->setLazyLoader(&Impl, /*context*/0);
+ conformance->setState(ProtocolConformanceState::Complete);
conformances.push_back(conformance);
}
@@ -7286,6 +7287,9 @@
void ClangImporter::Implementation::finishPendingActions() {
while (true) {
+ // The odd shape of this loop comes from previously having more than one
+ // possible kind of pending action. It's left this way to make it easy to
+ // add another one back in an `else if` clause.
if (!RegisteredExternalDecls.empty()) {
if (hasFinishedTypeChecking()) {
RegisteredExternalDecls.clear();
@@ -7297,22 +7301,22 @@
if (!nominal->hasDelayedMembers())
typeResolver->resolveExternalDeclImplicitMembers(nominal);
}
- } else if (!DelayedProtocolConformances.empty()) {
- NormalProtocolConformance *conformance =
- DelayedProtocolConformances.pop_back_val();
- finishProtocolConformance(conformance);
} else {
break;
}
}
}
-/// Finish the given protocol conformance (for an imported type)
-/// by filling in any missing witnesses.
-void ClangImporter::Implementation::finishProtocolConformance(
- NormalProtocolConformance *conformance) {
+void ClangImporter::Implementation::finishNormalConformance(
+ NormalProtocolConformance *conformance,
+ uint64_t unused) {
+ (void)unused;
const ProtocolDecl *proto = conformance->getProtocol();
+ PrettyStackTraceType trace(SwiftContext, "completing conformance for",
+ conformance->getType());
+ PrettyStackTraceDecl traceTo("... to", proto);
+
// Create witnesses for requirements not already met.
for (auto req : proto->getMembers()) {
auto valueReq = dyn_cast<ValueDecl>(req);
diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h
index 25c964d..174e075 100644
--- a/lib/ClangImporter/ImporterImpl.h
+++ b/lib/ClangImporter/ImporterImpl.h
@@ -496,9 +496,6 @@
/// External Decls that we have imported but not passed to the ASTContext yet.
SmallVector<Decl *, 4> RegisteredExternalDecls;
- /// Protocol conformances that may be missing witnesses.
- SmallVector<NormalProtocolConformance *, 4> DelayedProtocolConformances;
-
unsigned NumCurrentImportingEntities = 0;
/// Mapping from delayed conformance IDs to the set of delayed
@@ -517,7 +514,6 @@
void startedImportingEntity();
void finishedImportingEntity();
void finishPendingActions();
- void finishProtocolConformance(NormalProtocolConformance *conformance);
struct ImportingEntityRAII {
Implementation &Impl;
@@ -567,10 +563,6 @@
RegisteredExternalDecls.push_back(D);
}
- void scheduleFinishProtocolConformance(NormalProtocolConformance *C) {
- DelayedProtocolConformances.push_back(C);
- }
-
/// \brief Retrieve the Clang AST context.
clang::ASTContext &getClangASTContext() const {
return Instance->getASTContext();
@@ -1115,6 +1107,9 @@
const Decl *D, uint64_t contextData,
SmallVectorImpl<ProtocolConformance *> &Conformances) override;
+ void finishNormalConformance(NormalProtocolConformance *conformance,
+ uint64_t unused) override;
+
template <typename DeclTy, typename ...Targs>
DeclTy *createDeclWithClangNode(ClangNode ClangN, Accessibility access,
Targs &&... Args) {
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index cc1c307..42a4640 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -161,7 +161,7 @@
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
"-warnings-as-errors", "-suppress-warnings");
}
-
+
// Check for missing debug option when verifying debug info.
if (Args.hasArg(options::OPT_verify_debug_info)) {
bool hasDebugOption = true;
@@ -172,6 +172,18 @@
diags.diagnose(SourceLoc(),
diag::verify_debug_info_requires_debug_option);
}
+
+ for (const Arg *A : make_range(Args.filtered_begin(options::OPT_D),
+ Args.filtered_end())) {
+ StringRef name = A->getValue();
+ if (name.find('=') != StringRef::npos)
+ diags.diagnose(SourceLoc(),
+ diag::cannot_assign_value_to_conditional_compilation_flag,
+ name);
+ else if (!Lexer::isIdentifier(name))
+ diags.diagnose(SourceLoc(), diag::invalid_conditional_compilation_flag,
+ name);
+ }
}
/// Creates an appropriate ToolChain for a given driver and target triple.
@@ -1128,6 +1140,17 @@
OI.CompilerMode = OutputInfo::Mode::SingleCompile;
break;
+ // BEGIN APPLE-ONLY OUTPUT ACTIONS
+ case options::OPT_index_file:
+ OI.CompilerMode = OutputInfo::Mode::SingleCompile;
+ OI.CompilerOutputType = types::TY_IndexData;
+ break;
+ // END APPLE-ONLY OUTPUT ACTIONS
+
+ case options::OPT_update_code:
+ OI.CompilerOutputType = types::TY_Remapping;
+ OI.LinkAction = LinkKind::None;
+ break;
case options::OPT_parse:
case options::OPT_typecheck:
case options::OPT_dump_parse:
@@ -1300,6 +1323,27 @@
OI.SelectedSanitizer);
}
+static void
+currentDependsOnPCHIfPresent(JobAction *PCH,
+ std::unique_ptr<Action> &Current,
+ ActionList &Actions) {
+ if (PCH) {
+ // FIXME: When we have a PCH job, it's officially owned by the Actions
+ // array; but it's also a secondary input to each of the current
+ // JobActions, which means that we need to flip the "owns inputs" bit
+ // on the JobActions so they don't try to free it. That in turn means
+ // we need to transfer ownership of all the JobActions' existing
+ // inputs to the Actions array, since the JobActions either own or
+ // don't own _all_ of their inputs. Ownership can't vary
+ // input-by-input.
+ auto *job = cast<JobAction>(Current.get());
+ auto inputs = job->getInputs();
+ Actions.append(inputs.begin(), inputs.end());
+ job->setOwnsInputs(false);
+ job->addInput(PCH);
+ }
+}
+
void Driver::buildActions(const ToolChain &TC,
const DerivedArgList &Args,
const InputFileList &Inputs,
@@ -1364,6 +1408,7 @@
Current.reset(new CompileJobAction(Current.release(),
types::TY_LLVM_BC,
previousBuildState));
+ currentDependsOnPCHIfPresent(PCH, Current, Actions);
AllModuleInputs.push_back(Current.get());
Current.reset(new BackendJobAction(Current.release(),
OI.CompilerOutputType, 0));
@@ -1371,23 +1416,9 @@
Current.reset(new CompileJobAction(Current.release(),
OI.CompilerOutputType,
previousBuildState));
+ currentDependsOnPCHIfPresent(PCH, Current, Actions);
AllModuleInputs.push_back(Current.get());
}
- if (PCH) {
- // FIXME: When we have a PCH job, it's officially owned by the Actions
- // array; but it's also a secondary input to each of the current
- // JobActions, which means that we need to flip the "owns inputs" bit
- // on the JobActions so they don't try to free it. That in turn means
- // we need to transfer ownership of all the JobActions' existing
- // inputs to the Actions array, since the JobActions either own or
- // don't own _all_ of their inputs. Ownership can't vary
- // input-by-input.
- auto *job = cast<JobAction>(Current.get());
- auto inputs = job->getInputs();
- Actions.append(inputs.begin(), inputs.end());
- job->setOwnsInputs(false);
- job->addInput(PCH);
- }
AllLinkerInputs.push_back(Current.release());
break;
}
@@ -1420,6 +1451,7 @@
case types::TY_ClangModuleFile:
case types::TY_SwiftDeps:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_PCH:
case types::TY_ImportedModules:
case types::TY_TBD:
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index eafeb20..c2fd1d8 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -231,6 +231,13 @@
case types::TY_TBD:
FrontendModeOption = "-emit-tbd";
break;
+
+ // BEGIN APPLE-ONLY OUTPUT TYPES
+ case types::TY_IndexData:
+ FrontendModeOption = "-typecheck";
+ break;
+ // END APPLE-ONLY OUTPUT TYPES
+
case types::TY_Remapping:
FrontendModeOption = "-update-code";
break;
@@ -311,6 +318,12 @@
break;
}
case OutputInfo::Mode::SingleCompile: {
+ if (context.Output.getPrimaryOutputType() == types::TY_IndexData) {
+ if (Arg *A = context.Args.getLastArg(options::OPT_index_file_path)) {
+ Arguments.push_back("-primary-file");
+ Arguments.push_back(A->getValue());
+ }
+ }
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.InputActions.size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
@@ -456,6 +469,11 @@
if (context.Args.hasArg(options::OPT_embed_bitcode_marker))
Arguments.push_back("-embed-bitcode-marker");
+ if (context.Args.hasArg(options::OPT_index_store_path)) {
+ context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
+ Arguments.push_back("-index-system-modules");
+ }
+
return II;
}
@@ -541,6 +559,7 @@
case types::TY_SIL:
case types::TY_SIB:
case types::TY_PCH:
+ case types::TY_IndexData:
llvm_unreachable("Cannot be output from backend job");
case types::TY_Swift:
case types::TY_dSYM:
@@ -824,6 +843,7 @@
Arguments);
addInputsOfType(Arguments, context.InputActions, types::TY_ObjCHeader);
+ context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
if (job.isPersistentPCH()) {
Arguments.push_back("-emit-pch");
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index e6b87da..d0b60bc 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -92,6 +92,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
return false;
case types::TY_INVALID:
llvm_unreachable("Invalid type ID.");
@@ -128,6 +129,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_ModuleTrace:
return false;
case types::TY_INVALID:
@@ -165,6 +167,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_ModuleTrace:
return false;
case types::TY_INVALID:
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 1763da2..826f24e 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -169,6 +169,11 @@
Opts.GroupInfoPath = A->getValue();
}
+ if (const Arg *A = Args.getLastArg(OPT_index_store_path)) {
+ Opts.IndexStorePath = A->getValue();
+ }
+ Opts.IndexSystemModules |= Args.hasArg(OPT_index_system_modules);
+
Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil);
Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil);
@@ -1143,6 +1148,9 @@
if (const Arg *A = Args.getLastArg(OPT_target_cpu))
Opts.TargetCPU = A->getValue();
+ if (const Arg *A = Args.getLastArg(OPT_index_store_path))
+ Opts.IndexStorePath = A->getValue();
+
for (const Arg *A : make_range(Args.filtered_begin(OPT_Xcc),
Args.filtered_end())) {
Opts.ExtraArgs.push_back(A->getValue());
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index 0704189..7075aa6 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -97,6 +97,12 @@
if (!Invocation.getFrontendOptions().ModuleDocOutputPath.empty())
Invocation.getLangOptions().AttachCommentsToDecls = true;
+ // If we are doing index-while-building, configure lexing and parsing to
+ // remember comments.
+ if (!Invocation.getFrontendOptions().IndexStorePath.empty()) {
+ Invocation.getLangOptions().AttachCommentsToDecls = true;
+ }
+
Context.reset(new ASTContext(Invocation.getLangOptions(),
Invocation.getSearchPathOptions(),
SourceMgr, Diagnostics));
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index 1168a59..882b8ab 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -5,6 +5,7 @@
TBD.cpp
DEPENDS SwiftOptions
LINK_LIBRARIES
+ swiftIndex
swiftIDE
swiftTBDGen swiftIRGen swiftSIL swiftSILGen swiftSILOptimizer
swiftDemangling
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 28ca3ab..bdf06df 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -48,6 +48,7 @@
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/Frontend/SerializedDiagnosticConsumer.h"
#include "swift/Immediate/Immediate.h"
+#include "swift/Index/IndexRecord.h"
#include "swift/Option/Options.h"
#include "swift/Migrator/FixitFilter.h"
#include "swift/Migrator/Migrator.h"
@@ -368,6 +369,10 @@
LLVM_BUILTIN_TRAP;
}
+static bool emitIndexData(SourceFile *PrimarySourceFile,
+ const CompilerInvocation &Invocation,
+ CompilerInstance &Instance);
+
static void countStatsPostSema(UnifiedStatsReporter &Stats,
CompilerInstance& Instance) {
auto &C = Stats.getFrontendCounters();
@@ -646,8 +651,16 @@
(void)emitLoadedModuleTrace(Context, *Instance.getDependencyTracker(),
opts);
- if (Context.hadError())
+ bool shouldIndex = !opts.IndexStorePath.empty();
+
+ if (Context.hadError()) {
+ if (shouldIndex) {
+ // Emit the index store data even if there were compiler errors.
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return true;
+ }
// FIXME: This is still a lousy approximation of whether the module file will
// be externally consumed.
@@ -661,6 +674,10 @@
if (!opts.ObjCHeaderOutputPath.empty())
return printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(),
opts.ImplicitObjCHeaderPath, moduleIsPublic);
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return Context.hadError();
}
@@ -858,8 +875,13 @@
serialize(DC, serializationOpts, SM.get());
}
- if (Action == FrontendOptions::EmitModuleOnly)
+ if (Action == FrontendOptions::EmitModuleOnly) {
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return Context.hadError();
+ }
}
assert(Action >= FrontendOptions::EmitSIL &&
@@ -918,6 +940,13 @@
&HashGlobal);
}
+ // Walk the AST for indexing after IR generation. Walking it before seems
+ // to cause miscompilation issues.
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
+
// Just because we had an AST error it doesn't mean we can't performLLVM.
bool HadError = Instance.getASTContext().hadError();
@@ -975,6 +1004,52 @@
opts.getSingleOutputFilename(), Stats) || HadError;
}
+static bool emitIndexData(SourceFile *PrimarySourceFile,
+ const CompilerInvocation &Invocation,
+ CompilerInstance &Instance) {
+ const FrontendOptions &opts = Invocation.getFrontendOptions();
+ assert(!opts.IndexStorePath.empty());
+ // FIXME: provide index unit token(s) explicitly and only use output file
+ // paths as a fallback.
+
+ bool isDebugCompilation;
+ switch (Invocation.getSILOptions().Optimization) {
+ case SILOptions::SILOptMode::NotSet:
+ case SILOptions::SILOptMode::None:
+ case SILOptions::SILOptMode::Debug:
+ isDebugCompilation = true;
+ break;
+ case SILOptions::SILOptMode::Optimize:
+ case SILOptions::SILOptMode::OptimizeUnchecked:
+ isDebugCompilation = false;
+ break;
+ }
+
+ if (PrimarySourceFile) {
+ if (index::indexAndRecord(
+ PrimarySourceFile, opts.getSingleOutputFilename(),
+ opts.IndexStorePath, opts.IndexSystemModules,
+ isDebugCompilation, Invocation.getTargetTriple(),
+ *Instance.getDependencyTracker())) {
+ return true;
+ }
+ } else {
+ StringRef moduleToken = opts.ModuleOutputPath;
+ if (moduleToken.empty())
+ moduleToken = opts.getSingleOutputFilename();
+
+ if (index::indexAndRecord(Instance.getMainModule(), opts.OutputFilenames,
+ moduleToken, opts.IndexStorePath,
+ opts.IndexSystemModules,
+ isDebugCompilation, Invocation.getTargetTriple(),
+ *Instance.getDependencyTracker())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Returns true if an error occurred.
static bool dumpAPI(ModuleDecl *Mod, StringRef OutDir) {
using namespace llvm::sys;
@@ -1209,6 +1284,7 @@
DependencyTracker depTracker;
if (!Invocation.getFrontendOptions().DependenciesFilePath.empty() ||
!Invocation.getFrontendOptions().ReferenceDependenciesFilePath.empty() ||
+ !Invocation.getFrontendOptions().IndexStorePath.empty() ||
!Invocation.getFrontendOptions().LoadedModuleTracePath.empty()) {
Instance->setDependencyTracker(&depTracker);
}
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index d91c5a8..47aee9a 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -1,6 +1,7 @@
add_swift_library(swiftIndex STATIC
Index.cpp
IndexDataConsumer.cpp
+ IndexRecord.cpp
IndexSymbol.cpp
LINK_LIBRARIES
swiftAST)
diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp
new file mode 100644
index 0000000..91be812
--- /dev/null
+++ b/lib/Index/IndexRecord.cpp
@@ -0,0 +1,747 @@
+//===--- IndexRecord.cpp --------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Index/IndexRecord.h"
+#include "swift/AST/ASTContext.h"
+#include "swift/AST/Decl.h"
+#include "swift/AST/Expr.h"
+#include "swift/AST/Module.h"
+#include "swift/AST/ParameterList.h"
+#include "swift/AST/Pattern.h"
+#include "swift/AST/Stmt.h"
+#include "swift/AST/Types.h"
+#include "swift/AST/DiagnosticsFrontend.h"
+#include "swift/AST/ModuleLoader.h"
+#include "swift/ClangImporter/ClangModule.h"
+#include "swift/Index/Index.h"
+#include "swift/Strings.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Index/IndexRecordWriter.h"
+#include "clang/Index/IndexUnitWriter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Path.h"
+
+using namespace swift;
+using namespace swift::index;
+using clang::index::IndexUnitWriter;
+using clang::index::IndexRecordWriter;
+using clang::index::SymbolRole;
+using clang::index::SymbolRoleSet;
+
+//===----------------------------------------------------------------------===//
+// Index data collection and record writing
+//===----------------------------------------------------------------------===//
+
+namespace {
+class SymbolTracker {
+public:
+ struct SymbolRelation {
+ size_t symbolIndex;
+ SymbolRoleSet roles;
+
+ llvm::hash_code hash() const { return llvm::hash_combine(symbolIndex, roles); }
+ };
+ struct SymbolOccurrence {
+ size_t symbolIndex;
+ SymbolRoleSet roles;
+ unsigned line;
+ unsigned column;
+ SmallVector<SymbolRelation, 3> related;
+
+ llvm::hash_code hash() const {
+ auto hash = llvm::hash_combine(symbolIndex, roles, line, column);
+ for (auto &relation : related) {
+ hash = llvm::hash_combine(hash, relation.hash());
+ }
+ return hash;
+ }
+ };
+ struct Symbol {
+ StringRef name;
+ StringRef USR;
+ StringRef group;
+
+ SymbolInfo symInfo;
+ unsigned isTestCandidate : 1;
+
+ llvm::hash_code hash() const {
+ return llvm::hash_combine(
+ name, USR, group,
+ static_cast<unsigned>(symInfo.Kind),
+ static_cast<unsigned>(symInfo.SubKind),
+ symInfo.Properties, isTestCandidate);
+ }
+ };
+
+ Symbol *getSymbol(size_t index) {
+ assert(index < symbols.size());
+ return &symbols[index];
+ }
+
+ ArrayRef<SymbolOccurrence> getOccurrences() {
+ if (!sorted) {
+ std::stable_sort(occurrences.begin(), occurrences.end(),
+ [](const SymbolOccurrence &a, const SymbolOccurrence& b) {
+ if (a.line < b.line)
+ return true;
+ if (b.line < a.line)
+ return false;
+ return a.column < b.column;
+ });
+ sorted = true;
+ }
+ return occurrences;
+ }
+
+ size_t addSymbol(const IndexRelation &indexSym) {
+ auto pair = USRToSymbol.insert(std::make_pair(indexSym.USR.data(),
+ symbols.size()));
+ if (pair.second) {
+ Symbol symbol{indexSym.name,
+ indexSym.USR,
+ indexSym.group,
+ indexSym.symInfo,
+ 0};
+ recordHash = llvm::hash_combine(recordHash, symbol.hash());
+ symbols.push_back(std::move(symbol));
+ }
+
+ return pair.first->second;
+ }
+
+ void addOccurrence(const IndexSymbol &indexOccur) {
+ sorted = false;
+
+ SmallVector<SymbolRelation, 3> relations;
+ for(IndexRelation indexRel: indexOccur.Relations) {
+ relations.push_back({addSymbol(indexRel), indexRel.roles});
+ }
+
+ occurrences.push_back({/*symbolIndex=*/addSymbol(indexOccur),
+ indexOccur.roles,
+ indexOccur.line,
+ indexOccur.column,
+ std::move(relations)});
+
+ recordHash = llvm::hash_combine(recordHash, occurrences.back().hash());
+ }
+
+ llvm::hash_code hashRecord() const { return recordHash; }
+
+private:
+ llvm::DenseMap<const char *, size_t> USRToSymbol;
+ std::vector<Symbol> symbols;
+ std::vector<SymbolOccurrence> occurrences;
+ bool sorted = false;
+ llvm::hash_code recordHash = 0;
+};
+
+class IndexRecordingConsumer : public IndexDataConsumer {
+ SymbolTracker record;
+ // Keep a USR map to uniquely identify Decls.
+ // FIXME: if we just passed the original Decl * through we could use that,
+ // which would also let us avoid producing the USR/Name/etc. for decls unless
+ // we actually need it (once per Decl instead of once per occurrence).
+ std::vector<IndexSymbol> symbolStack;
+
+ std::function<void(SymbolTracker &)> onFinish;
+
+public:
+ IndexRecordingConsumer(std::function<void(SymbolTracker &)> onFinish)
+ : onFinish(std::move(onFinish)) {}
+
+ void failed(StringRef error) override {
+ // FIXME: expose errors?
+ }
+
+ bool recordHash(StringRef hash, bool isKnown) override { return true; }
+ bool startDependency(StringRef name, StringRef path, bool isClangModule,
+ bool isSystem, StringRef hash) override {
+ return true;
+ }
+ bool finishDependency(bool isClangModule) override { return true; }
+ Action startSourceEntity(const IndexSymbol &symbol) override {
+ symbolStack.push_back(symbol);
+ return Action::Continue;
+ }
+ bool finishSourceEntity(SymbolInfo sym, SymbolRoleSet roles) override {
+ IndexSymbol symbol = std::move(symbolStack.back());
+ symbolStack.pop_back();
+ assert(!symbol.USR.empty());
+ record.addOccurrence(symbol);
+ return true;
+ }
+
+ void finish() override { onFinish(record); }
+};
+
+class StdlibGroupsIndexRecordingConsumer : public IndexDataConsumer {
+ llvm::StringMap<std::unique_ptr<SymbolTracker>> TrackerByGroup;
+ // Keep a USR map to uniquely identify Decls.
+ // FIXME: if we just passed the original Decl * through we could use that,
+ // which would also let us avoid producing the USR/Name/etc. for decls unless
+ // we actually need it (once per Decl instead of once per occurrence).
+ std::vector<IndexSymbol> symbolStack;
+
+ std::function<bool(StringRef groupName, SymbolTracker &)> onFinish;
+
+public:
+ StdlibGroupsIndexRecordingConsumer(std::function<bool(StringRef groupName, SymbolTracker &)> onFinish)
+ : onFinish(std::move(onFinish)) {}
+
+ void failed(StringRef error) override {
+ // FIXME: expose errors?
+ }
+
+ bool recordHash(StringRef hash, bool isKnown) override { return true; }
+ bool startDependency(StringRef name, StringRef path, bool isClangModule,
+ bool isSystem, StringRef hash) override {
+ return true;
+ }
+ bool finishDependency(bool isClangModule) override { return true; }
+ Action startSourceEntity(const IndexSymbol &symbol) override {
+ symbolStack.push_back(symbol);
+ return Action::Continue;
+ }
+ bool finishSourceEntity(SymbolInfo sym, SymbolRoleSet roles) override {
+ IndexSymbol symbol = std::move(symbolStack.back());
+ symbolStack.pop_back();
+ assert(!symbol.USR.empty());
+ StringRef groupName = findGroupForSymbol(symbol);
+ auto &tracker = TrackerByGroup[groupName];
+ if (!tracker) {
+ tracker = llvm::make_unique<SymbolTracker>();
+ }
+ tracker->addOccurrence(symbol);
+ return true;
+ }
+
+ void finish() override {
+ for (auto &pair : TrackerByGroup) {
+ StringRef groupName = pair.first();
+ SymbolTracker &tracker = *pair.second;
+ bool cont = onFinish(groupName, tracker);
+ if (!cont)
+ break;
+ }
+ }
+
+private:
+ StringRef findGroupForSymbol(const IndexSymbol &sym);
+
+};
+} // end anonymous namespace
+
+static StringRef findGroupNameForDecl(const Decl *D) {
+ if (!D || isa<ModuleDecl>(D) || isa<TopLevelCodeDecl>(D))
+ return StringRef();
+
+ auto groupNameOpt = D->getGroupName();
+ if (groupNameOpt)
+ return *groupNameOpt;
+
+ return findGroupNameForDecl(D->getDeclContext()->getInnermostDeclarationDeclContext());
+}
+
+StringRef StdlibGroupsIndexRecordingConsumer::findGroupForSymbol(const IndexSymbol &sym) {
+ bool isDeclOrDef = sym.roles & ((SymbolRoleSet)SymbolRole::Declaration | (SymbolRoleSet)SymbolRole::Definition);
+ if (isDeclOrDef) {
+ if (!sym.group.empty())
+ return sym.group;
+ return findGroupNameForDecl(sym.decl);
+ }
+
+ for (auto &rel : sym.Relations) {
+ if (!rel.group.empty())
+ return rel.group;
+ if (rel.decl)
+ return findGroupNameForDecl(rel.decl);
+ }
+ llvm_unreachable("did not find group name for reference");
+}
+
+static bool writeRecord(SymbolTracker &record, std::string Filename,
+ std::string indexStorePath, DiagnosticEngine *diags,
+ std::string &outRecordFile) {
+ if (record.getOccurrences().empty()) {
+ outRecordFile = std::string();
+ return false;
+ }
+
+ IndexRecordWriter recordWriter(indexStorePath);
+ std::string error;
+ auto result = recordWriter.beginRecord(
+ Filename, record.hashRecord(), error, &outRecordFile);
+ switch (result) {
+ case IndexRecordWriter::Result::Failure:
+ diags->diagnose(SourceLoc(), diag::error_write_index_record, error);
+ return true;
+ case IndexRecordWriter::Result::AlreadyExists:
+ return false;
+ case IndexRecordWriter::Result::Success:
+ break;
+ }
+
+ for (auto &occurrence : record.getOccurrences()) {
+ SmallVector<clang::index::writer::SymbolRelation, 3> relations;
+ for(SymbolTracker::SymbolRelation symbolRelation: occurrence.related) {
+ relations.push_back({record.getSymbol(symbolRelation.symbolIndex), symbolRelation.roles});
+ }
+
+ recordWriter.addOccurrence(
+ record.getSymbol(occurrence.symbolIndex), occurrence.roles,
+ occurrence.line, occurrence.column, relations);
+ }
+
+ result = recordWriter.endRecord(error,
+ [&](clang::index::writer::OpaqueDecl opaqueSymbol,
+ SmallVectorImpl<char> &scratch) {
+ auto *symbol = static_cast<const SymbolTracker::Symbol *>(opaqueSymbol);
+ clang::index::writer::Symbol result;
+ result.SymInfo = symbol->symInfo;
+ result.Name = symbol->name;
+ result.USR = symbol->USR;
+ result.CodeGenName = ""; // FIXME
+ return result;
+ });
+
+ if (result == IndexRecordWriter::Result::Failure) {
+ diags->diagnose(SourceLoc(), diag::error_write_index_record, error);
+ return true;
+ }
+
+ return false;
+}
+
+static std::unique_ptr<IndexRecordingConsumer>
+makeRecordingConsumer(std::string Filename, std::string indexStorePath,
+ DiagnosticEngine *diags,
+ std::string *outRecordFile,
+ bool *outFailed) {
+ return llvm::make_unique<IndexRecordingConsumer>([=](SymbolTracker &record) {
+ *outFailed = writeRecord(record, Filename, indexStorePath, diags,
+ *outRecordFile);
+ });
+}
+
+static bool
+recordSourceFile(SourceFile *SF, StringRef indexStorePath,
+ DiagnosticEngine &diags,
+ llvm::function_ref<void(StringRef, StringRef)> callback) {
+ std::string recordFile;
+ bool failed = false;
+ auto consumer = makeRecordingConsumer(SF->getFilename(), indexStorePath,
+ &diags, &recordFile, &failed);
+ indexSourceFile(SF, /*Hash=*/"", *consumer);
+
+ if (!failed && !recordFile.empty())
+ callback(recordFile, SF->getFilename());
+ return failed;
+}
+
+//===----------------------------------------------------------------------===//
+// Index unit file writing
+//===----------------------------------------------------------------------===//
+
+// Used to get std::string pointers to pass as writer::OpaqueModule.
+namespace {
+class StringScratchSpace {
+ std::vector<const std::string *> StrsCreated;
+
+public:
+ const std::string *createString(StringRef str) {
+ auto *s = new std::string(str);
+ StrsCreated.push_back(s);
+ return s;
+ }
+
+ ~StringScratchSpace() {
+ for (auto *str : StrsCreated)
+ delete str;
+ }
+};
+}
+
+static clang::index::writer::ModuleInfo
+getModuleInfoFromOpaqueModule(clang::index::writer::OpaqueModule mod,
+ SmallVectorImpl<char> &Scratch) {
+ clang::index::writer::ModuleInfo info;
+ info.Name = *static_cast<const std::string*>(mod);
+ return info;
+}
+
+static bool
+emitDataForSwiftSerializedModule(ModuleDecl *module,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &parentUnitWriter);
+
+static void addModuleDependencies(ArrayRef<ModuleDecl::ImportedModule> imports,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &unitWriter,
+ StringScratchSpace &moduleNameScratch) {
+ auto &fileMgr = clangCI.getFileManager();
+
+ for (auto &import : imports) {
+ ModuleDecl *mod = import.second;
+ if (mod->getNameStr() == SWIFT_ONONE_SUPPORT)
+ continue; // ignore the Onone support library.
+ if (mod->isSwiftShimsModule())
+ continue;
+
+ for (auto *FU : mod->getFiles()) {
+ switch (FU->getKind()) {
+ case FileUnitKind::Source:
+ case FileUnitKind::Derived:
+ case FileUnitKind::Builtin:
+ break;
+ case FileUnitKind::SerializedAST:
+ case FileUnitKind::ClangModule: {
+ auto *LFU = cast<LoadedFile>(FU);
+ if (auto *F = fileMgr.getFile(LFU->getFilename())) {
+ std::string moduleName = mod->getNameStr();
+ bool withoutUnitName = true;
+ if (FU->getKind() == FileUnitKind::ClangModule) {
+ withoutUnitName = false;
+ auto clangModUnit = cast<ClangModuleUnit>(LFU);
+ if (auto clangMod = clangModUnit->getUnderlyingClangModule()) {
+ moduleName = clangMod->getTopLevelModuleName();
+ // FIXME: clang's -Rremarks do not seem to go through Swift's
+ // diagnostic emitter.
+ clang::index::emitIndexDataForModuleFile(clangMod,
+ clangCI, unitWriter);
+ }
+ } else {
+ // Serialized AST file.
+ // Only index system modules (essentially stdlib and overlays).
+ // We don't officially support binary swift modules, so normally
+ // the index data for user modules would get generated while
+ // building them.
+ if (mod->isSystemModule() && indexSystemModules) {
+ emitDataForSwiftSerializedModule(mod, indexStorePath,
+ indexSystemModules,
+ targetTriple, clangCI, diags,
+ unitWriter);
+ withoutUnitName = false;
+ }
+ }
+ clang::index::writer::OpaqueModule opaqMod =
+ moduleNameScratch.createString(moduleName);
+ unitWriter.addASTFileDependency(F, mod->isSystemModule(), opaqMod,
+ withoutUnitName);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/// \returns true if an error occurred.
+static bool
+emitDataForSwiftSerializedModule(ModuleDecl *module,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &parentUnitWriter) {
+ StringRef filename = module->getModuleFilename();
+ std::string moduleName = module->getNameStr();
+
+ std::string error;
+ auto isUptodateOpt = parentUnitWriter.isUnitUpToDateForOutputFile(/*FilePath=*/filename,
+ /*TimeCompareFilePath=*/filename, error);
+ if (!isUptodateOpt.hasValue()) {
+ diags.diagnose(SourceLoc(), diag::error_index_failed_status_check, error);
+ return true;
+ }
+ if (*isUptodateOpt)
+ return false;
+
+ // FIXME: Would be useful for testing if swift had clang's -Rremark system so
+ // we could output a remark here that we are going to create index data for
+ // a module file.
+
+ // Pairs of (recordFile, groupName).
+ std::vector<std::pair<std::string, std::string>> records;
+
+ if (!module->isStdlibModule()) {
+ std::string recordFile;
+ bool failed = false;
+ auto consumer = makeRecordingConsumer(filename, indexStorePath,
+ &diags, &recordFile, &failed);
+ indexModule(module, /*Hash=*/"", *consumer);
+
+ if (failed)
+ return true;
+
+ records.emplace_back(recordFile, moduleName);
+ } else {
+ // Record stdlib groups as if they were submodules.
+
+ auto makeSubmoduleNameFromGroupName = [](StringRef groupName, SmallString<128> &buf) {
+ buf += "Swift";
+ if (groupName.empty())
+ return;
+ buf += '.';
+ for (char ch : groupName) {
+ if (ch == '/')
+ buf += '.';
+ else if (ch == ' ' || ch == '-')
+ buf += '_';
+ else
+ buf += ch;
+ }
+ };
+ auto appendGroupNameForFilename = [](StringRef groupName, SmallString<256> &buf) {
+ if (groupName.empty())
+ return;
+ buf += '_';
+ for (char ch : groupName) {
+ if (ch == '/' || ch ==' ')
+ buf += '_';
+ else
+ buf += ch;
+ }
+ };
+
+ bool failed = false;
+ StdlibGroupsIndexRecordingConsumer groupIndexConsumer([&](StringRef groupName, SymbolTracker &tracker) -> bool {
+ SmallString<128> moduleName;
+ makeSubmoduleNameFromGroupName(groupName, moduleName);
+ SmallString<256> fileNameWithGroup = filename;
+ appendGroupNameForFilename(groupName, fileNameWithGroup);
+
+ std::string outRecordFile;
+ failed = failed || writeRecord(tracker, fileNameWithGroup.str(), indexStorePath, &diags, outRecordFile);
+ if (failed)
+ return false;
+ records.emplace_back(outRecordFile, moduleName.str());
+ return true;
+ });
+ indexModule(module, /*Hash=*/"", groupIndexConsumer);
+ if (failed)
+ return true;
+ }
+
+ auto &fileMgr = clangCI.getFileManager();
+ bool isSystem = module->isSystemModule();
+ // FIXME: Get real values for the following.
+ StringRef swiftVersion;
+ StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot;
+ std::string indexUnitToken = module->getModuleFilename();
+ // For indexing serialized modules 'debug compilation' is irrelevant, so
+ // set it to true by default.
+ bool isDebugCompilation = true;
+
+ IndexUnitWriter unitWriter(fileMgr, indexStorePath,
+ "swift", swiftVersion, indexUnitToken, moduleName,
+ /*MainFile=*/nullptr, isSystem, /*IsModuleUnit=*/true,
+ isDebugCompilation, targetTriple, sysrootPath, getModuleInfoFromOpaqueModule);
+
+ const clang::FileEntry *FE = fileMgr.getFile(filename);
+ bool isSystemModule = module->isSystemModule();
+ for (auto &pair : records) {
+ std::string &recordFile = pair.first;
+ std::string &groupName = pair.second;
+ if (recordFile.empty())
+ continue;
+ clang::index::writer::OpaqueModule mod = &groupName;
+ unitWriter.addRecordFile(recordFile, FE, isSystemModule, mod);
+ }
+
+ SmallVector<ModuleDecl::ImportedModule, 8> imports;
+ module->getImportedModules(imports, ModuleDecl::ImportFilter::All);
+ StringScratchSpace moduleNameScratch;
+ addModuleDependencies(imports, indexStorePath, indexSystemModules,
+ targetTriple, clangCI, diags, unitWriter, moduleNameScratch);
+
+ if (unitWriter.write(error)) {
+ diags.diagnose(SourceLoc(), diag::error_write_index_unit, error);
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+recordSourceFileUnit(SourceFile *primarySourceFile, StringRef indexUnitToken,
+ StringRef indexStorePath, bool indexSystemModules,
+ bool isDebugCompilation, StringRef targetTriple,
+ ArrayRef<const clang::FileEntry *> fileDependencies,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags) {
+ auto &fileMgr = clangCI.getFileManager();
+ auto *module = primarySourceFile->getParentModule();
+ bool isSystem = module->isSystemModule();
+ auto *mainFile = fileMgr.getFile(primarySourceFile->getFilename());
+ // FIXME: Get real values for the following.
+ StringRef swiftVersion;
+ StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot;
+
+ IndexUnitWriter unitWriter(fileMgr, indexStorePath,
+ "swift", swiftVersion, indexUnitToken, module->getNameStr(),
+ mainFile, isSystem, /*isModuleUnit=*/false, isDebugCompilation,
+ targetTriple, sysrootPath, getModuleInfoFromOpaqueModule);
+
+ // Module dependencies.
+ SmallVector<ModuleDecl::ImportedModule, 8> imports;
+ primarySourceFile->getImportedModules(imports, ModuleDecl::ImportFilter::All);
+ StringScratchSpace moduleNameScratch;
+ addModuleDependencies(imports, indexStorePath, indexSystemModules,
+ targetTriple, clangCI, diags, unitWriter, moduleNameScratch);
+
+ // File dependencies.
+ for (auto *F : fileDependencies)
+ unitWriter.addFileDependency(F, /*FIXME:isSystem=*/false, /*Module=*/nullptr);
+
+ recordSourceFile(primarySourceFile, indexStorePath, diags,
+ [&](StringRef recordFile, StringRef filename) {
+ unitWriter.addRecordFile(recordFile, fileMgr.getFile(filename),
+ module->isSystemModule(), /*Module=*/nullptr);
+ });
+
+ std::string error;
+ if (unitWriter.write(error)) {
+ diags.diagnose(SourceLoc(), diag::error_write_index_unit, error);
+ return true;
+ }
+
+ return false;
+}
+
+// Not currently used, see related comments in the call sites.
+#if 0
+static void
+collectFileDependencies(llvm::SetVector<const clang::FileEntry *> &result,
+ const DependencyTracker &dependencyTracker,
+ ModuleDecl *module, clang::FileManager &fileMgr) {
+ for (auto *F : module->getFiles()) {
+ if (auto *SF = dyn_cast<SourceFile>(F)) {
+ if (auto *dep = fileMgr.getFile(SF->getFilename())) {
+ result.insert(dep);
+ }
+ }
+ }
+ for (StringRef filename : dependencyTracker.getDependencies()) {
+ if (auto *F = fileMgr.getFile(filename))
+ result.insert(F);
+ }
+}
+#endif
+
+//===----------------------------------------------------------------------===//
+// Indexing entry points
+//===----------------------------------------------------------------------===//
+
+bool index::indexAndRecord(SourceFile *primarySourceFile,
+ StringRef indexUnitToken,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker) {
+ auto &astContext = primarySourceFile->getASTContext();
+ auto &clangCI = astContext.getClangModuleLoader()->getClangInstance();
+ auto &diags = astContext.Diags;
+
+ std::string error;
+ if (IndexUnitWriter::initIndexDirectory(indexStorePath, error)) {
+ diags.diagnose(SourceLoc(), diag::error_create_index_dir, error);
+ return true;
+ }
+
+ llvm::SetVector<const clang::FileEntry *> fileDependencies;
+ // FIXME: This is not desirable because:
+ // 1. It picks shim header files as file dependencies
+ // 2. Having all the other swift files of the module as file dependencies ends
+ // up making all of them associated with all the other files as main files.
+ // It's better to associate each swift file with the unit that recorded it
+ // as the main one.
+ // Keeping the code in case we want to revisit.
+#if 0
+ auto *module = primarySourceFile->getParentModule();
+ collectFileDependencies(fileDependencies, dependencyTracker, module, fileMgr);
+#endif
+
+ return recordSourceFileUnit(primarySourceFile, indexUnitToken,
+ indexStorePath, indexSystemModules,
+ isDebugCompilation, targetTriple,
+ fileDependencies.getArrayRef(),
+ clangCI, diags);
+}
+
+bool index::indexAndRecord(ModuleDecl *module,
+ ArrayRef<std::string> indexUnitTokens,
+ StringRef moduleUnitToken,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker) {
+ auto &astContext = module->getASTContext();
+ auto &clangCI = astContext.getClangModuleLoader()->getClangInstance();
+ auto &diags = astContext.Diags;
+
+ std::string error;
+ if (IndexUnitWriter::initIndexDirectory(indexStorePath, error)) {
+ diags.diagnose(SourceLoc(), diag::error_create_index_dir, error);
+ return true;
+ }
+
+ // Add the current module's source files to the dependencies.
+ llvm::SetVector<const clang::FileEntry *> fileDependencies;
+ // FIXME: This is not desirable because:
+ // 1. It picks shim header files as file dependencies
+ // 2. Having all the other swift files of the module as file dependencies ends
+ // up making all of them associated with all the other files as main files.
+ // It's better to associate each swift file with the unit that recorded it
+ // as the main one.
+ // Keeping the code in case we want to revisit.
+#if 0
+ collectFileDependencies(fileDependencies, dependencyTracker, module, fileMgr);
+#endif
+
+ // Write a unit for each source file.
+ unsigned unitIndex = 0;
+ for (auto *F : module->getFiles()) {
+ if (auto *SF = dyn_cast<SourceFile>(F)) {
+ if (unitIndex == indexUnitTokens.size()) {
+ diags.diagnose(SourceLoc(), diag::error_index_inputs_more_than_outputs);
+ return true;
+ }
+ if (recordSourceFileUnit(SF, indexUnitTokens[unitIndex],
+ indexStorePath, indexSystemModules,
+ isDebugCompilation, targetTriple,
+ fileDependencies.getArrayRef(),
+ clangCI, diags))
+ return true;
+ unitIndex += 1;
+ }
+ }
+
+ // In the case where inputs are swift modules, like in the merge-module step,
+ // ignore the inputs; associated unit files for the modules' source inputs
+ // should have been generated at swift module creation time.
+
+ return false;
+}
diff --git a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt
index 6ea47fa..590c5e9 100644
--- a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt
+++ b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt
@@ -107,7 +107,7 @@
static var __PrivA: NSOptions { get }
static var B: NSOptions { get }
}
-class __PrivCFType : _CFObject {
+class __PrivCFType {
}
@available(swift, obsoleted: 3, renamed: "__PrivCFType")
typealias __PrivCFTypeRef = __PrivCFType
diff --git a/test/ClangImporter/Inputs/custom-modules/Protocols.h b/test/ClangImporter/Inputs/custom-modules/Protocols.h
index 43ad828..552adbd 100644
--- a/test/ClangImporter/Inputs/custom-modules/Protocols.h
+++ b/test/ClangImporter/Inputs/custom-modules/Protocols.h
@@ -9,3 +9,12 @@
Class <FooProto, AnotherProto> _Nonnull processComboType(Class <FooProto, AnotherProto> _Nonnull);
Class <AnotherProto, FooProto> _Nonnull processComboType2(Class <AnotherProto, FooProto> _Nonnull);
+
+@protocol SubProto <FooProto>
+@end
+
+@interface ProtocolTestingBase
+@end
+
+@interface SubProtoImpl: ProtocolTestingBase <SubProto>
+@end
diff --git a/test/ClangImporter/protocol-conformance-in-extension.swift b/test/ClangImporter/protocol-conformance-in-extension.swift
new file mode 100644
index 0000000..69a4c83
--- /dev/null
+++ b/test/ClangImporter/protocol-conformance-in-extension.swift
@@ -0,0 +1,21 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t/a~partial.swiftmodule -I %S/Inputs/custom-modules -module-name TEST -primary-file %s
+// RUN: %target-swift-frontend -emit-module -o %t/test.swiftmodule -I %S/Inputs/custom-modules -module-name TEST %t/a~partial.swiftmodule
+
+// REQUIRES: objc_interop
+
+import TestProtocols
+
+// The protocol in the extension has to refine something that the base class
+// conforms to to trigger the error in rdar://problem/32346184.
+protocol SomeSwiftProto: Equatable {}
+extension ProtocolTestingBase: Equatable {
+ public static func ==(left: ProtocolTestingBase, right: ProtocolTestingBase) -> Bool {
+ return left === right
+ }
+}
+
+// The extension going through the typealias also makes a difference.
+typealias SpecialObject = SubProtoImpl
+extension SpecialObject: SomeSwiftProto {
+}
diff --git a/test/Driver/bridging-pch.swift b/test/Driver/bridging-pch.swift
index bb3ac15..dbb4a28 100644
--- a/test/Driver/bridging-pch.swift
+++ b/test/Driver/bridging-pch.swift
@@ -32,6 +32,12 @@
// PERSISTENT-YESPCHACT: 2: input, "{{.*}}bridging-pch.swift", swift
// PERSISTENT-YESPCHACT: 3: compile, {2, 1}, none
+// RUN: %swiftc_driver -c -driver-print-actions -embed-bitcode -import-objc-header %S/Inputs/bridging-header.h -pch-output-dir %t/pch %s 2>&1 | %FileCheck %s -check-prefix=PERSISTENT-YESPCHACTBC
+// PERSISTENT-YESPCHACTBC: 0: input, "{{.*}}Inputs/bridging-header.h", objc-header
+// PERSISTENT-YESPCHACTBC: 1: generate-pch, {0}, none
+// PERSISTENT-YESPCHACTBC: 2: input, "{{.*}}bridging-pch.swift", swift
+// PERSISTENT-YESPCHACTBC: 3: compile, {2, 1}, llvm-bc
+
// RUN: %swiftc_driver -typecheck -disable-bridging-pch -driver-print-actions -import-objc-header %S/Inputs/bridging-header.h -pch-output-dir %t/pch %s 2>&1 | %FileCheck %s -check-prefix=NOPCHACT
// RUN: %swiftc_driver -typecheck -driver-print-jobs -import-objc-header %S/Inputs/bridging-header.h -pch-output-dir %t/pch -disable-bridging-pch %s 2>&1 | %FileCheck %s -check-prefix=PERSISTENT-DISABLED-YESPCHJOB
diff --git a/test/Driver/options-repl.swift b/test/Driver/options-repl.swift
index 7967fdb..d980ae8 100644
--- a/test/Driver/options-repl.swift
+++ b/test/Driver/options-repl.swift
@@ -16,7 +16,7 @@
// RUN: %swift_driver -lldb-repl -### | %FileCheck -check-prefix=LLDB %s
-// RUN: %swift_driver -lldb-repl -DA,B,C -DD -L /path/to/libraries -L /path/to/more/libraries -F /path/to/frameworks -lsomelib -framework SomeFramework -sdk / -I "this folder" -module-name Test -target %target-triple -### | %FileCheck -check-prefix=LLDB-OPTS %s
+// RUN: %swift_driver -lldb-repl -D A -DB -D C -DD -L /path/to/libraries -L /path/to/more/libraries -F /path/to/frameworks -lsomelib -framework SomeFramework -sdk / -I "this folder" -module-name Test -target %target-triple -### | %FileCheck -check-prefix=LLDB-OPTS %s
// LLDB: lldb{{"?}} {{"?}}--repl=
// LLDB-NOT: -module-name
@@ -24,7 +24,7 @@
// LLDB-OPTS: lldb{{"?}} "--repl=
// LLDB-OPTS-DAG: -target {{[^ ]+}}
-// LLDB-OPTS-DAG: -D A,B,C -D D
+// LLDB-OPTS-DAG: -D A -D B -D C -D D
// LLDB-OPTS-DAG: -sdk /
// LLDB-OPTS-DAG: -L /path/to/libraries
// LLDB-OPTS-DAG: -L /path/to/more/libraries
diff --git a/test/Frontend/unknown-arguments.swift b/test/Frontend/unknown-arguments.swift
index d80a2a7..e8f8553 100644
--- a/test/Frontend/unknown-arguments.swift
+++ b/test/Frontend/unknown-arguments.swift
@@ -6,3 +6,9 @@
// RUN: not %swiftc_driver -c %s -o %t.o -Xfrontend -fake-frontend-arg -Xfrontend fakevalue 2>&1 | %FileCheck -check-prefix=XFRONTEND %s
// XFRONTEND: <unknown>:0: error: unknown argument: '-fake-frontend-arg'
+
+// RUN: not %swiftc_driver -D Correct -DAlsoCorrect -D@#%! -D Swift=Cool -D-D -c %s -o %t.o 2>&1 | %FileCheck -check-prefix=INVALID-COND %s
+// INVALID-COND: <unknown>:0: error: conditional compilation flags must be valid Swift identifiers (rather than '@#%!')
+// INVALID-COND-NEXT: <unknown>:0: warning: conditional compilation flags do not have values in Swift; they are either present or absent (rather than 'Swift=Cool')
+// INVALID-COND-NEXT: <unknown>:0: error: conditional compilation flags must be valid Swift identifiers (rather than '-D')
+
diff --git a/test/Index/Store/Inputs/ClangModuleA.h b/test/Index/Store/Inputs/ClangModuleA.h
new file mode 100644
index 0000000..ea06ce2
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleA.h
@@ -0,0 +1 @@
+void funcA(void);
diff --git a/test/Index/Store/Inputs/ClangModuleB.h b/test/Index/Store/Inputs/ClangModuleB.h
new file mode 100644
index 0000000..ce316e2
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleB.h
@@ -0,0 +1,2 @@
+@import ClangModuleA;
+void funcB(void);
diff --git a/test/Index/Store/Inputs/ClangModuleCSub1.h b/test/Index/Store/Inputs/ClangModuleCSub1.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleCSub1.h
diff --git a/test/Index/Store/Inputs/ClangModuleCSub2.h b/test/Index/Store/Inputs/ClangModuleCSub2.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleCSub2.h
diff --git a/test/Index/Store/Inputs/SwiftModuleA.swift b/test/Index/Store/Inputs/SwiftModuleA.swift
new file mode 100644
index 0000000..59e7758
--- /dev/null
+++ b/test/Index/Store/Inputs/SwiftModuleA.swift
@@ -0,0 +1 @@
+public func funcSwiftA() {}
diff --git a/test/Index/Store/Inputs/SwiftModuleB.swift b/test/Index/Store/Inputs/SwiftModuleB.swift
new file mode 100644
index 0000000..b12db68
--- /dev/null
+++ b/test/Index/Store/Inputs/SwiftModuleB.swift
@@ -0,0 +1,2 @@
+import SwiftModuleA
+public func funcSwiftB() { funcSwiftA() }
diff --git a/test/Index/Store/Inputs/bridge-head.h b/test/Index/Store/Inputs/bridge-head.h
new file mode 100644
index 0000000..b25d652
--- /dev/null
+++ b/test/Index/Store/Inputs/bridge-head.h
@@ -0,0 +1 @@
+#include "bridge-include.h"
diff --git a/test/Index/Store/Inputs/bridge-include.h b/test/Index/Store/Inputs/bridge-include.h
new file mode 100644
index 0000000..55a0722
--- /dev/null
+++ b/test/Index/Store/Inputs/bridge-include.h
@@ -0,0 +1,2 @@
+int includedFunc(int a);
+int MY_CONST = 2;
\ No newline at end of file
diff --git a/test/Index/Store/Inputs/module.modulemap b/test/Index/Store/Inputs/module.modulemap
new file mode 100644
index 0000000..a25324f
--- /dev/null
+++ b/test/Index/Store/Inputs/module.modulemap
@@ -0,0 +1,20 @@
+module ClangModuleA {
+ header "ClangModuleA.h"
+ export *
+}
+module ClangModuleB {
+ header "ClangModuleB.h"
+ export *
+}
+
+module ClangModuleC {
+ module Sub1 {
+ header "ClangModuleCSub1.h"
+ export *
+ }
+
+ module Sub2 {
+ header "ClangModuleCSub2.h"
+ export *
+ }
+}
diff --git a/test/Index/Store/driver-index.swift b/test/Index/Store/driver-index.swift
new file mode 100644
index 0000000..b8007d0
--- /dev/null
+++ b/test/Index/Store/driver-index.swift
@@ -0,0 +1,2 @@
+// RUN: %swiftc_driver -driver-print-jobs -index-file -index-file-path %s %S/Inputs/SwiftModuleA.swift %s -o %t.output_for_index -index-store-path %t.index_store -module-name driver_index 2>&1 | %FileCheck %s
+// CHECK: {{.*}}swift -frontend -typecheck {{.*}}-primary-file {{.*}}driver-index.swift {{.*}}SwiftModuleA.swift {{.*}}driver-index.swift {{.*}}-o {{.*}}.output_for_index {{.*}}-index-store-path {{.*}}.index_store -index-system-modules
diff --git a/test/Index/Store/output-failure.swift b/test/Index/Store/output-failure.swift
new file mode 100644
index 0000000..24167e3
--- /dev/null
+++ b/test/Index/Store/output-failure.swift
@@ -0,0 +1,41 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir %t/idx
+
+// Before indexing, do a dry-run to ensure any clang modules are cached. We
+// want to isolate the error that comes from swift's indexing support, not
+// any failures indexing a clang module.
+// RUN: %target-swift-frontend %s -typecheck
+
+// RUN: chmod -w %t/idx
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/dir.txt || chmod +w %t/idx
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx
+// RUN: %FileCheck %s -check-prefix=DIR_ERR < %t/dir.txt
+// DIR_ERR: error: creating index directory
+
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o
+// test -s %t/idx/*/units/oof.o*
+
+// RUN: chmod -w %t/idx/*/units
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/file.txt || chmod +w %t/idx/*/units
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx/*/units
+// RUN: %FileCheck %s -check-prefix=FILE_ERR < %t/file.txt
+// FILE_ERR: error: writing index unit file
+
+// RUN: rm -rf %t/idx/*/records/*
+// RUN: chmod -x %t/idx/*/records
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/record.txt || chmod +x %t/idx/*/records
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +x %t/idx/*/records
+// RUN: %FileCheck %s -check-prefix=RECORD_ERR < %t/record.txt
+// RECORD_ERR: error: writing index record file
+
+// RUN: rm -rf %t/idx/*/records/*
+// RUN: chmod -w %t/idx/*/records
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/record2.txt || chmod +w %t/idx/*/records
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx/*/records
+// RUN: %FileCheck %s -check-prefix=RECORD_ERR < %t/record2.txt
+
+func foo() {}
diff --git a/test/Index/Store/record-comments.swift b/test/Index/Store/record-comments.swift
new file mode 100644
index 0000000..5d356f1
--- /dev/null
+++ b/test/Index/Store/record-comments.swift
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t.o -typecheck %s
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: record-comments.swift
+// CHECK: ------------
+// CHECK: comment-tag/Swift | <no-name> | t:this_is_a_tag | <no-cgname> | Def -
+// CHECK: comment-tag/Swift | <no-name> | t:and_another | <no-cgname> | Def -
+// CHECK: ------------
+
+/// Hello
+/// - Tag: this_is_a_tag
+/// - Tag: and_another
+func foo() {}
+// CHECK: [[@LINE-3]]:5 | comment-tag/Swift | t:this_is_a_tag | Def | rel: 0
+// CHECK: [[@LINE-3]]:5 | comment-tag/Swift | t:and_another | Def | rel: 0
+// CHECK: [[@LINE-3]]:6 | function/Swift |
diff --git a/test/Index/Store/record-dependency.swift b/test/Index/Store/record-dependency.swift
new file mode 100644
index 0000000..6c3777b
--- /dev/null
+++ b/test/Index/Store/record-dependency.swift
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// CHECK: DEPEND START
+// CHECK: Record | user | {{.*}}record-dependency.swift | record-dependency.swift-
+// CHECK: DEPEND END
+
+// RUN: echo 'func bar() {}' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx2 -emit-module -module-name main -emit-module-path %t/main.swiftmodule %s %t/s2.swift -o %t/file.o -o %t/s2.o
+// RUN: c-index-test core -print-unit %t/idx2 | %FileCheck %s -check-prefix=TWO_RECORDS
+// TWO_RECORDS: file.o-
+// TWO_RECORDS: DEPEND START
+// TWO_RECORDS: Record | user | {{.*}}record-dependency.swift | record-dependency.swift-
+// TWO_RECORDS: DEPEND END
+// TWO_RECORDS: s2.o-
+// TWO_RECORDS: DEPEND START
+// TWO_RECORDS: Record | user | {{.*}}s2.swift | s2.swift-
+// TWO_RECORDS: DEPEND END
+
+// XFAIL: linux
+
+func foo() {}
diff --git a/test/Index/Store/record-empty.swift b/test/Index/Store/record-empty.swift
new file mode 100644
index 0000000..c7bdd9e
--- /dev/null
+++ b/test/Index/Store/record-empty.swift
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck -primary-file %s
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// CHECK-NOT: Record{{.*}}record-empty
+
+// XFAIL: linux
diff --git a/test/Index/Store/record-hashing.swift b/test/Index/Store/record-hashing.swift
new file mode 100644
index 0000000..665d4a3
--- /dev/null
+++ b/test/Index/Store/record-hashing.swift
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: echo "func foo() {}" > %t/theinput.swift
+
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: ls %t/idx/*/records/* | grep "theinput.swift" | count 1
+// RUN: cp -r %t/idx %t/idx-orig
+
+// RUN: touch %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// No change in record.
+
+// RUN: echo '// Comment.' >> %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// No change in record.
+
+// RUN: echo 'func goo() {}' >> %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: not diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// RUN: ls %t/idx/*/records/* | grep "theinput.swift" | count 2
+// Changed! Wrote a new record.
diff --git a/test/Index/Store/record-sourcefile.swift b/test/Index/Store/record-sourcefile.swift
new file mode 100644
index 0000000..129f7cc
--- /dev/null
+++ b/test/Index/Store/record-sourcefile.swift
@@ -0,0 +1,155 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx1 -o %t/file.o -typecheck %s
+// RUN: %target-swift-frontend -index-store-path %t/idx2 -o %t/file.o -typecheck -primary-file %s
+// RUN: c-index-test core -print-record %t/idx1 | %FileCheck %s
+// RUN: c-index-test core -print-record %t/idx2 | %FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: record-sourcefile.swift
+// CHECK: ------------
+// CHECK: struct/Swift | S1 | s:4file2S1V | <no-cgname> | Def,Ref,RelCont -
+// CHECK: instance-method/acc-get/Swift | getter:property | s:4file2S1V8propertySifg | <no-cgname> | Def,Ref,Call,Impl,RelChild,RelRec,RelCall,RelAcc,RelCont -
+// CHECK: instance-property/Swift | property | [[property_USR:s:4file2S1V8propertySiv]] | <no-cgname> | Def,Ref,Read,RelChild,RelCont -
+// CHECK: static-method/acc-get/Swift | getter:staticProperty | s:4file2S1V14staticPropertySifg | <no-cgname> | Def,Ref,Call,Impl,RelChild,RelRec,RelCall,RelAcc,RelCont -
+// CHECK: static-property/Swift | staticProperty | s:{{.*}} | <no-cgname> | Def,Ref,Read,RelChild,RelCont -
+// CHECK: instance-property/Swift | computedPropertyGetSet | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: struct/Swift | Int | s:Si | <no-cgname> | Ref -
+// CHECK: instance-method/acc-get/Swift | getter:computedPropertyGetSet | s:4file2S1V22computedPropertyGetSetSifg | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-set/Swift | setter:computedPropertyGetSet | s:4file2S1V22computedPropertyGetSetSifs | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-property/Swift | computedPropertyWillDid | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-willset/Swift | willSet:computedPropertyWillDid | s:4file2S1V23computedPropertyWillDidSifw | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-didset/Swift | didSet:computedPropertyWillDid | s:4file2S1V23computedPropertyWillDidSifW | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-property/Swift | computedPropertyAddressor | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-addr/Swift | <no-name> | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-mutaddr/Swift | <no-name> | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: static-method/Swift | staticMethod() | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-property/subscript/Swift | subscript(_:) | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-get/Swift | getter:subscript(_:) | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: protocol/Swift | P1 | s:{{.*}} | <no-cgname> | Def -
+// CHECK: type-alias/associated-type/Swift | AT | s:{{.*}} | <no-cgname> | Def,Ref,RelChild -
+// CHECK: type-alias/Swift | TA | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: class/Swift | C1 | s:{{.*}} | <no-cgname> | Def,Ref,RelBase,RelCont -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,Ref,Call,Dyn,RelChild,RelRec,RelCall,RelCont -
+// CHECK: class/Swift | C2 | s:{{.*}} | <no-cgname> | Def -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,Dyn,RelChild,RelOver -
+// CHECK: function/Swift | takeC1(x:) | s:{{.*}} | <no-cgname> | Def -
+// CHECK: instance-method(test)/Swift | testFoo() | s:{{.*}} | <no-cgname> | Def,Dyn,RelChild -
+// CHECK: ------------
+
+// CHECK: [[@LINE+1]]:8 | struct/Swift | [[S1_USR:s:.*]] | Def | rel: 0
+struct S1 {
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[property_USR]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ let property = 1
+// CHECK: [[@LINE+2]]:14 | static-property/Swift | [[staticProperty_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ static let staticProperty = 2
+
+// CHECK: [[@LINE+3]]:7 | instance-property/Swift | [[computedPropertyGetSet_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+// CHECK: [[@LINE+1]]:31 | struct/Swift | s:Si | Ref | rel: 0
+ var computedPropertyGetSet: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-get/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyGetSet_USR]]
+ get { return 1 }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-set/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyGetSet_USR]]
+ set { }
+ }
+
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[computedPropertyWillDid_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ var computedPropertyWillDid: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-willset/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyWillDid_USR]]
+ willSet { }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-didset/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyWillDid_USR]]
+ didSet { }
+ }
+
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[computedPropertyAddressor_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ var computedPropertyAddressor: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-addr/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyAddressor_USR]]
+ unsafeAddress { }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-mutaddr/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyAddressor_USR]]
+ unsafeMutableAddress { }
+ }
+
+// CHECK: [[@LINE+2]]:8 | instance-method/Swift | [[method_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ func method() {
+ _ = self
+// CHECK: [[@LINE+4]]:9 | instance-method/acc-get/Swift | s:{{.*}} | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[method_USR]]
+// CHECK-NEXT: RelRec | [[S1_USR]]
+// CHECK: [[@LINE+1]]:9 | instance-property/Swift | s:{{.*}} | Ref,Read,RelCont | rel: 1
+ _ = property
+ }
+
+// CHECK: [[@LINE+2]]:15 | static-method/Swift | [[staticMethod_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ static func staticMethod() {
+// CHECK: [[@LINE+5]]:9 | struct/Swift | s:{{.*}} | Ref,RelCont | rel: 1
+// CHECK: [[@LINE+4]]:12 | static-method/acc-get/Swift | s:{{.*}} | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[staticMethod_USR]]
+// CHECK-NEXT: RelRec | [[S1_USR]]
+// CHECK: [[@LINE+1]]:12 | static-property/Swift | s:{{.*}} | Ref,Read,RelCont | rel: 1
+ _ = S1.staticProperty
+ }
+
+// CHECK: [[@LINE+4]]:3 | instance-property/subscript/Swift | [[S1_subscript_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+// CHECK: [[@LINE+2]]:28 | instance-method/acc-get/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[S1_subscript_USR]]
+ subscript(x: Int) -> Int { return 1 }
+}
+
+// CHECK: [[@LINE+1]]:10 | protocol/Swift | [[P1_USR:s:.*]] | Def | rel: 0
+protocol P1 {
+// CHECK: [[@LINE+2]]:18 | type-alias/associated-type/Swift | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[P1_USR]]
+ associatedtype AT
+// CHECK: [[@LINE+3]]:13 | type-alias/Swift | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[P1_USR]]
+// CHECK: [[@LINE+1]]:18 | type-alias/associated-type/Swift | s:{{.*}} | Ref | rel: 0
+ typealias TA = AT
+}
+
+// CHECK: [[@LINE+1]]:7 | class/Swift | [[C1_USR:s:.*]] | Def | rel: 0
+class C1 {
+// CHECK: [[@LINE+2]]:8 | instance-method/Swift | [[C1_foo_USR:s:.*]] | Def,Dyn,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[C1_USR]]
+ func method() {}
+}
+// CHECK: [[@LINE+3]]:7 | class/Swift | [[C2_USR:s:.*]] | Def | rel: 0
+// CHECK: [[@LINE+2]]:12 | class/Swift | [[C1_USR]] | Ref,RelBase | rel: 1
+// CHECK-NEXT: RelBase | [[C2_USR]]
+class C2 : C1 {
+// CHECK: [[@LINE+3]]:17 | instance-method/Swift | s:{{.*}} | Def,Dyn,RelChild,RelOver | rel: 2
+// CHECK-NEXT: RelOver | [[C1_foo_USR]]
+// CHECK-NEXT: RelChild | [[C2_USR]]
+ override func method() {}
+}
+
+// CHECK: [[@LINE+2]]:6 | function/Swift | [[takeC1_USR:s:.*]] | Def | rel: 0
+// CHECK: [[@LINE+1]]:16 | class/Swift | s:{{.*}} | Ref,RelCont | rel: 1
+func takeC1(x: C1) {
+// CHECK: [[@LINE+3]]:5 | instance-method/Swift | s:{{.*}} | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[takeC1_USR]]
+// CHECK-NEXT: RelRec | [[C1_USR]]
+ x.method()
+}
+
+func test1() {}
+class XCTestCase {}
+class MyTestCase: XCTestCase {
+// CHECK: [[@LINE+2]]:8 | instance-method(test)/Swift | s:{{.*}} | Def,Dyn,RelChild | rel: 1
+// CHECK-NEXT: RelChild | s:4file10MyTestCaseC
+ func testFoo() { test1() }
+}
diff --git a/test/Index/Store/record-with-compile-error.swift b/test/Index/Store/record-with-compile-error.swift
new file mode 100644
index 0000000..0cb017d
--- /dev/null
+++ b/test/Index/Store/record-with-compile-error.swift
@@ -0,0 +1,12 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s -verify
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s
+
+// CHECK: function/Swift | test1() | [[TEST1_FUNC:.*]] | <no-cgname> | Def
+// CHECK: [[@LINE+1]]:6 | function/Swift | [[TEST1_FUNC]]
+func test1() {
+ unresolved() // expected-error {{use of unresolved identifier}}
+}
diff --git a/test/Index/Store/unit-from-compile.swift b/test/Index/Store/unit-from-compile.swift
new file mode 100644
index 0000000..2ddfb6e
--- /dev/null
+++ b/test/Index/Store/unit-from-compile.swift
@@ -0,0 +1,24 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend -c -index-store-path %t/idx %s -o %t/file1.o -module-name some_module_test
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// RUN: %target-swift-frontend -c -index-store-path %t/idx_opt %s -o %t/file1.o -module-name some_module_test -O
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=OPT
+
+// CHECK: file1.o
+// CHECK: provider: swift
+// CHECK: is-system: 0
+// CHECK: is-module: 0
+// CHECK: module-name: some_module_test
+// CHECK: has-main: 1
+// CHECK: main-path: {{.*}}/unit-from-compile.swift
+// CHECK: out-file: {{.*}}/file1.o
+// CHECK: is-debug: 1
+
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}/Swift.swiftmodule |
+// CHECK: DEPEND END (1)
+
+// OPT: is-debug: 1
diff --git a/test/Index/Store/unit-multiple-sourcefiles.swift b/test/Index/Store/unit-multiple-sourcefiles.swift
new file mode 100644
index 0000000..a35350b
--- /dev/null
+++ b/test/Index/Store/unit-multiple-sourcefiles.swift
@@ -0,0 +1,33 @@
+// XFAIL: linux
+
+//===--- Building source files separately with a module merge at the end
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s1.swift %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %t/s1.swift %t/s2.swift -o %t/s1.o -c -module-name main -emit-module -emit-module-path %t/s1.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swift -primary-file %t/s2.swift -o %t/s2.o -c -module-name main -emit-module -emit-module-path %t/s2.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swiftmodule %t/s2.swiftmodule -emit-module -o %t/main.swiftmodule -module-name main
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+//===--- Building source files together (e.g. WMO)
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s1.swift %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swift %t/s2.swift -o %t/s1.o -o %t/s2.o -c -module-name main -emit-module -emit-module-path %t/main.swiftmodule
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+// CHECK-NOT: main.swiftmodule-{{[A-Z0-9]*}}
+
+// CHECK: s1.o-{{[A-Z0-9]*}}
+// CHECK: --------
+// CHECK: out-file: {{.*}}s1.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: s2.o-{{[A-Z0-9]*}}
+// CHECK: --------
+// CHECK: out-file: {{.*}}s2.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
diff --git a/test/Index/Store/unit-one-file-multi-file-invocation.swift b/test/Index/Store/unit-one-file-multi-file-invocation.swift
new file mode 100644
index 0000000..65d08c0
--- /dev/null
+++ b/test/Index/Store/unit-one-file-multi-file-invocation.swift
@@ -0,0 +1,23 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %swiftc_driver -index-file -index-file-path %s %s %S/Inputs/SwiftModuleA.swift -module-name unit_one_test -o %t.output_for_index -index-store-path %t/idx
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=UNIT
+
+// UNIT-NOT: SwiftShims
+
+// UNIT: [[SWIFT:Swift.swiftmodule-[A-Z0-9]*]]
+// UNIT: DEPEND START
+// UNIT: Record | system | Swift.Math.Floating | {{.*}}Swift.swiftmodule | Swift.swiftmodule_Math_Floating-{{.*}}
+// UNIT: Record | system | Swift.String | {{.*}}Swift.swiftmodule | Swift.swiftmodule_String-{{.*}}
+// UNIT: DEPEND END
+
+// UNIT: unit-one-file-multi-file-invocation{{.*}}.output_for_index
+// UNIT: DEPEND START
+// UNIT: Unit | system |{{.*}}/Swift.swiftmodule | [[SWIFT]]
+// UNIT: Record | user |{{.*}}/unit-one-file-multi-file-invocation.swift |
+// UNIT: DEPEND END (2)
+
+func test1() {
+ funcSwiftA()
+}
diff --git a/test/Index/Store/unit-one-sourcefile.swift b/test/Index/Store/unit-one-sourcefile.swift
new file mode 100644
index 0000000..d0acc59
--- /dev/null
+++ b/test/Index/Store/unit-one-sourcefile.swift
@@ -0,0 +1,29 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -o %t/file1.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s %t/s2.swift -o %t/file1.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -primary-file %t/s2.swift -o %t/file2.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE2
+
+// FILE1: file1.o-{{[A-Z0-9]*}}
+// FILE1: --------
+// FILE1: out-file: {{.*}}file1.o
+// FILE1: DEPEND START
+// FILE1: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE1: DEPEND END
+
+// FILE2: file2.o-{{[A-Z0-9]*}}
+// FILE2: --------
+// FILE2: out-file: {{.*}}file2.o
+// FILE2: DEPEND START
+// FILE2: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE2: DEPEND END
diff --git a/test/Index/Store/unit-pcm-dependency.swift b/test/Index/Store/unit-pcm-dependency.swift
new file mode 100644
index 0000000..c9721ba
--- /dev/null
+++ b/test/Index/Store/unit-pcm-dependency.swift
@@ -0,0 +1,79 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s -o %t/s1.o -I %S/Inputs -typecheck -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// If the module cache already exists, the pcm gets indexed.
+// RUN: rm -rf %t/idx
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s -o %t/s1.o -I %S/Inputs -typecheck -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// FIXME: index the bridging header!
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: echo 'import ClangModuleA' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s %t/s2.swift -o %t/s1.o -o %t/s2.o -I %S/Inputs -c -emit-module -module-name main -emit-module-path %t/main.swiftmodule -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx > %t/both.txt
+// RUN: %FileCheck %s -check-prefix=FILE1 < %t/both.txt
+// RUN: %FileCheck %s -check-prefix=FILE2 < %t/both.txt
+
+
+// XFAIL: linux
+
+import ClangModuleB
+import ClangModuleC.Sub1
+import ClangModuleC.Sub2
+
+func test() {
+ funcA()
+ funcB()
+}
+
+// FILE1: ClangModuleA-
+// FILE1: --------
+// FILE1: is-system: 0
+// FILE1: has-main: 0
+// FILE1: DEPEND START
+// FILE1: Record | user | {{.*}}ClangModuleA.h | ClangModuleA.h-
+// FILE1: DEPEND END
+
+// FILE1: ClangModuleB-
+// FILE1: --------
+// FILE1: is-system: 0
+// FILE1: has-main: 0
+// FILE1: DEPEND START
+// FILE1: Unit | user | ClangModuleA | {{.*}}ClangModuleA-{{.*}}.pcm | ClangModuleA-{{.*}}.pcm-
+// FILE1: Record | user | {{.*}}ClangModuleB.h | ClangModuleB.h-
+// FILE1: DEPEND END
+
+// FILE1: s1.o-
+// FILE1: --------
+// FILE1: has-main: 1
+// FILE1: DEPEND START
+// FILE1-NOT: ClangModuleA.h
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Unit | system | Swift | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Unit | user | ClangModuleB | {{.*}}ClangModuleB-{{[A-Z0-9]*}}.pcm | ClangModuleB-{{[A-Z0-9]*}}.pcm-
+// FILE1: Unit | user | ClangModuleC | {{.*}}ClangModuleC-{{[A-Z0-9]*}}.pcm | ClangModuleC-{{[A-Z0-9]*}}.pcm-
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Record | user | {{.*}}unit-pcm-dependency.swift | unit-pcm-dependency.swift-
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: DEPEND END (4)
+
+// FILE2-NOT: main.swiftmodule-
+
+// FILE2: s2.o-
+// FILE2: --------
+// FILE2: has-main: 1
+// FILE2: out-file: {{.*}}s2.o
+// FILE2: DEPEND START
+// FILE2-NOT: ClangModuleB.h
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: Unit | system | Swift | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: Unit | user | ClangModuleA | {{.*}}ClangModuleA-{{[A-Z0-9]*}}.pcm | ClangModuleA-{{[A-Z0-9]*}}.pcm-
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: DEPEND END
diff --git a/test/Index/Store/unit-swiftmodule-dependency.swift b/test/Index/Store/unit-swiftmodule-dependency.swift
new file mode 100644
index 0000000..df54f92
--- /dev/null
+++ b/test/Index/Store/unit-swiftmodule-dependency.swift
@@ -0,0 +1,57 @@
+// RUN: rm -rf %t && mkdir %t
+
+// RUN: %target-swift-frontend -index-store-path %t/idx %S/Inputs/SwiftModuleA.swift -emit-module -o %t/SwiftModuleA.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %S/Inputs/SwiftModuleB.swift -emit-module -o %t/SwiftModuleB.swiftmodule -I %t
+
+// RUN: echo 'import SwiftModuleA' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s %t/s2.swift -c -o %t/s1.o -o %t/s2.o -I %t -emit-module -module-name main -emit-module-path %t/main.swiftmodule
+
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+// XFAIL: linux
+
+import SwiftModuleA
+import SwiftModuleB
+
+func test() {
+ funcSwiftA()
+ funcSwiftB()
+}
+
+// CHECK: [[MODA:SwiftModuleA.swiftmodule-[A-Z0-9]*]]
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/SwiftModuleA.swiftmodule
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: [[MODB:SwiftModuleB.swiftmodule-[A-Z0-9]*]]
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/SwiftModuleB.swiftmodule
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK-NOT: main.swiftmodule-
+
+// CHECK: s1.o-
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/s1.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleB | {{.*}}/SwiftModuleB.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: s2.o-
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/s2.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
diff --git a/test/Index/Store/unit-with-bridging-header.swift b/test/Index/Store/unit-with-bridging-header.swift
new file mode 100644
index 0000000..f335802
--- /dev/null
+++ b/test/Index/Store/unit-with-bridging-header.swift
@@ -0,0 +1,49 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-pch -index-store-path %t/idx -o %t/bridge-head.pch %S/Inputs/bridge-head.h
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %t/bridge-head.pch -primary-file %s -o %t/s1.o -index-store-path %t/idx
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s --check-prefix=PCH-RECORD
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s --check-prefix=PCH-UNIT
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %S/Inputs/bridge-head.h -primary-file %s -o %t/s1.o -index-store-path %t/idx2
+// RUN: c-index-test core -print-unit %t/idx2 | %FileCheck --check-prefix=TEXTUAL-UNIT %s
+
+// PCH-RECORD: bridge-include.h
+// PCH-RECORD: ------------
+// PCH-RECORD: function/C | includedFunc | {{.*}} | <no-cgname> | Decl -
+// PCH-RECORD: variable/C | MY_CONST | {{.*}} | <no-cgname> | Def -
+// PCH-RECORD: ------------
+// PCH-RECORD: 1:5 | function/C | {{.*}} | Decl | rel: 0
+// PCH-RECORD: 2:5 | variable/C | {{.*}} | Def | rel: 0
+
+// PCH-UNIT: bridge-head.pch-
+// PCH-UNIT: --------
+// PCH-UNIT: has-main: 0
+// PCH-UNIT: DEPEND START
+// PCH-UNIT: Record | user | {{.*}}bridge-include.h | bridge-include.h-
+// PCH-UNIT: File | user | {{.*}}bridge-head.h |
+// PCH-UNIT: File | user | {{.*}}module.modulemap |
+// PCH-UNIT: DEPEND END (3)
+// PCH-UNIT: INCLUDE START
+// PCH-UNIT: {{.*}}bridge-head.h:1 | {{.*}}bridge-include.h
+// PCH-UNIT: INCLUDE END (1)
+
+// PCH-UNIT: s1.o-
+// PCH-UNIT: --------
+// PCH-UNIT: has-main: 1
+// PCH-UNIT: DEPEND START
+// PCH-UNIT: Unit | system | {{.*}}Swift.swiftmodule |
+// PCH-UNIT: Unit | user | {{.*}}bridge-head.pch | bridge-head.pch-
+// PCH-UNIT: Record | user | {{.*}}unit-with-bridging-header.swift | unit-with-bridging-header.swift-
+// PCH-UNIT: DEPEND END (3)
+
+// TEXTUAL-UNIT: s1.o-
+// TEXTUAL-UNIT: --------
+// TEXTUAL-UNIT: has-main: 1
+// TEXTUAL-UNIT: DEPEND START
+// TEXTUAL-UNIT: Unit | system | {{.*}}Swift.swiftmodule |
+// TEXTUAL-UNIT: Record | user | {{.*}}unit-with-bridging-header.swift | unit-with-bridging-header.swift-
+// TEXTUAL-UNIT: DEPEND END (2)
+
+func test() {}