in lib/Index/IndexDatastore.cpp [456:691]
void StoreUnitRepo::registerUnit(StringRef unitName, bool isInitialScan, std::shared_ptr<UnitProcessingSession> processSession) {
std::string Error;
auto optModTime = IdxStore->getUnitModificationTime(unitName, Error);
if (!optModTime) {
if (UseExplicitOutputUnits) {
// It is normal to setup the list of units before the data is generated.
LOG_INFO_FUNC(Low, "(explicit-units mode) error getting mod time for unit '" << unitName << "':" << Error);
} else {
LOG_WARN_FUNC("error getting mod time for unit '" << unitName << "':" << Error);
}
return;
}
auto unitModTime = toTimePoint(optModTime.getValue());
std::unique_ptr<IndexUnitReader> readerPtr;
auto getUnitReader = [&]() -> IndexUnitReader& {
if (!readerPtr) {
readerPtr.reset(new IndexUnitReader(*IdxStore, unitName, Error));
if (readerPtr->isInvalid()) {
LOG_WARN_FUNC("error loading unit '" << unitName << "':" << Error);
}
}
return *readerPtr;
};
IDCode unitCode;
bool needDatabaseUpdate;
Optional<bool> optIsSystem;
Optional<bool> PrevHasTestSymbols;
IDCode PrevMainFileCode;
IDCode PrevOutFileCode;
Optional<StoreUnitInfo> StoreUnitInfoOpt;
std::vector<CanonicalFilePath> UserFileDepends;
std::vector<IDCode> UserUnitDepends;
SmallVector<std::string, 16> unitDependencies;
// Returns true if an error occurred.
auto importUnit = [&]() -> bool {
ImportTransaction import(SymIndex->getDBase());
UnitDataImport unitImport(import, unitName, unitModTime);
unitCode = unitImport.getUnitCode();
needDatabaseUpdate = !unitImport.isUpToDate();
optIsSystem = unitImport.getIsSystem();
if (!needDatabaseUpdate) {
PrevMainFileCode = unitImport.getPrevMainFileCode();
PrevOutFileCode = unitImport.getPrevOutFileCode();
PrevHasTestSymbols = unitImport.getHasTestSymbols();
return false;
}
auto &Reader = getUnitReader();
if (Reader.isInvalid())
return true;
SymbolProviderKind symProviderKind = getSymbolProviderKindFromIdentifer(Reader.getProviderIdentifier()).getValue();
optIsSystem = Reader.isSystemUnit();
unitImport.setIsSystemUnit(optIsSystem.getValue());
unitImport.setSymbolProviderKind(symProviderKind);
unitImport.setTarget(Reader.getTarget());
StringRef WorkDir = Reader.getWorkingDirectory();
CanonicalFilePath CanonMainFile;
bool hasMainFile = Reader.hasMainFile();
if (hasMainFile) {
CanonMainFile = CanonPathCache->getCanonicalPath(Reader.getMainFilePath(), WorkDir);
unitImport.setMainFile(CanonMainFile);
}
CanonicalFilePath CanonOutFile = CanonPathCache->getCanonicalPath(Reader.getOutputFile(), WorkDir);
unitImport.setOutFile(CanonOutFile);
CanonicalFilePath CanonSysroot = CanonPathCache->getCanonicalPath(Reader.getSysrootPath(), WorkDir);
unitImport.setSysroot(CanonSysroot);
// Collect the dependency info and process them outside of the libIndexStore callback.
// This is because processing populates the database and C++ exceptions can be thrown; libIndexStore builds with -fno-exceptions so we cannot
// be throwing C++ exceptions from inside its frames.
struct UnitDependencyInfo {
IndexUnitDependency::DependencyKind Kind;
bool IsSystem;
std::string FilePath;
std::string Name;
std::string ModuleName;
};
SmallVector<UnitDependencyInfo, 16> dependencies;
Reader.foreachDependency([&](IndexUnitDependency Dep)->bool {
dependencies.push_back(UnitDependencyInfo{Dep.getKind(), Dep.isSystem(), Dep.getFilePath(), Dep.getName(), Dep.getModuleName()});
return true;
});
for (const UnitDependencyInfo &dep : dependencies) {
switch (dep.Kind) {
case IndexUnitDependency::DependencyKind::Record: {
CanonicalFilePath CanonPath = CanonPathCache->getCanonicalPath(dep.FilePath, WorkDir);
if (CanonPath.empty())
break;
if (!dep.IsSystem)
UserFileDepends.push_back(CanonPath);
StringRef recordName = dep.Name;
StringRef moduleName = dep.ModuleName;
if (moduleName.empty()) {
// Workaround for swift compiler not associating the module name with records of swift files.
// FIXME: Fix this on swift compiler and remove this.
if (StringRef(CanonPath.getPath()).endswith(".swift")) {
moduleName = Reader.getModuleName();
}
}
bool isNewProvider;
IDCode providerCode = unitImport.addProviderDependency(recordName, CanonPath, moduleName, dep.IsSystem, &isNewProvider);
if (!isNewProvider)
break;
std::string Error;
auto Rec = StoreSymbolRecord::create(IdxStore, recordName, providerCode, symProviderKind, /*fileRefs=*/None);
if (!Rec) {
LOG_WARN_FUNC("error creating store symbol record: " << Error);
break;
}
SymIndex->importSymbols(import, Rec);
break;
}
case IndexUnitDependency::DependencyKind::Unit: {
unitDependencies.push_back(dep.Name);
IDCode unitDepCode = unitImport.addUnitDependency(dep.Name);
if (!dep.IsSystem)
UserUnitDepends.push_back(unitDepCode);
break;
}
case IndexUnitDependency::DependencyKind::File: {
CanonicalFilePath CanonPath = CanonPathCache->getCanonicalPath(dep.FilePath, WorkDir);
if (CanonPath.empty())
break;
if (!dep.IsSystem)
UserFileDepends.push_back(CanonPath);
unitImport.addFileDependency(CanonPath);
}
}
}
unitImport.commit();
StoreUnitInfoOpt = StoreUnitInfo{unitName, CanonMainFile, CanonOutFile, unitImport.getHasTestSymbols().getValue(), unitModTime};
import.commit();
return false;
};
if (importUnit())
return; // error occurred;
if (Delegate) {
if (!StoreUnitInfoOpt.hasValue()) {
ReadTransaction reader(SymIndex->getDBase());
CanonicalFilePath mainFile = reader.getFullFilePathFromCode(PrevMainFileCode);
CanonicalFilePath outFile = reader.getFullFilePathFromCode(PrevOutFileCode);
StoreUnitInfoOpt = StoreUnitInfo{unitName, mainFile, outFile, PrevHasTestSymbols.getValue(), unitModTime};
}
Delegate->processedStoreUnit(StoreUnitInfoOpt.getValue());
}
if (UseExplicitOutputUnits) {
// Unit dependencies, like PCH/modules, are not included in the explicit list,
// make sure to process them as we find them.
// We do this after finishing processing the dependent unit to avoid nested write transactions.
std::vector<UnitEventInfo> unitsNeedingUpdate;
{
ReadTransaction reader(SymIndex->getDBase());
auto needsUpdate = [&](StringRef unitName) -> bool {
if (processSession->hasEnqueuedUnitDependency(unitName)) {
// Avoid enqueuing the same dependency from multiple dependents.
return false;
}
UnitInfo info = reader.getUnitInfo(unitName);
if (info.isInvalid()) {
return true; // not registered yet.
}
std::string error;
auto optModTime = IdxStore->getUnitModificationTime(unitName, error);
if (!optModTime) {
LOG_WARN_FUNC("error getting mod time for unit '" << unitName << "':" << error);
return false;
}
auto unitModTime = toTimePoint(optModTime.getValue());
return info.ModTime != unitModTime;
};
for (const auto &unitName : unitDependencies) {
if (needsUpdate(unitName)) {
unitsNeedingUpdate.push_back(UnitEventInfo(IndexStore::UnitEvent::Kind::Added, unitName, isInitialScan, /*isDependency=*/true));
}
}
}
processSession->enqueue(std::move(unitsNeedingUpdate));
}
if (*optIsSystem || !EnableOutOfDateFileWatching)
return;
// Monitor user files of the unit.
// Get the user files if we didn't already go through them earlier.
if (!needDatabaseUpdate) {
auto &Reader = getUnitReader();
if (Reader.isInvalid())
return;
StringRef WorkDir = Reader.getWorkingDirectory();
Reader.foreachDependency([&](IndexUnitDependency Dep)->bool {
switch (Dep.getKind()) {
case IndexUnitDependency::DependencyKind::Unit:
if (!Dep.isSystem())
UserUnitDepends.push_back(makeIDCodeFromString(Dep.getName()));
break;
case IndexUnitDependency::DependencyKind::Record:
case IndexUnitDependency::DependencyKind::File: {
CanonicalFilePath CanonPath = CanonPathCache->getCanonicalPath(Dep.getFilePath(), WorkDir);
if (CanonPath.empty())
break;
if (!Dep.isSystem())
UserFileDepends.push_back(CanonPath);
}
}
return true;
});
}
auto localThis = shared_from_this();
auto unitMonitor = std::make_shared<UnitMonitor>(localThis);
unitMonitor->initialize(unitCode, unitName, unitModTime, UserFileDepends, UserUnitDepends, /*checkForOutOfDate=*/isInitialScan);
addUnitMonitor(unitCode, unitMonitor);
}