void StoreUnitRepo::registerUnit()

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);
}