Skip to content

Commit 2adc599

Browse files
authored
Merge pull request #185 from ahoppen/ahoppen/timestamp-api
Add an APIs to get the date at which the unit file that produced `SymbolLocation` was modified and the latest modification date of a unit that contains a given source file
2 parents b90ca2e + ba32ab7 commit 2adc599

File tree

9 files changed

+116
-1
lines changed

9 files changed

+116
-1
lines changed

Sources/ISDBTestSupport/TestLocation.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ extension SymbolLocation {
5151
public init(_ loc: TestLocation, moduleName: String = TestLocation.unknownModuleName, isSystem: Bool = false) {
5252
self.init(
5353
path: loc.url.path,
54+
timestamp: Date(),
5455
moduleName: moduleName,
5556
isSystem: isSystem,
5657
line: loc.line,

Sources/IndexStoreDB/IndexStoreDB.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
@_implementationOnly
1414
import CIndexStoreDB
15+
import Foundation
1516

1617
// For `strdup`
1718
#if canImport(Glibc)
@@ -448,6 +449,19 @@ public final class IndexStoreDB {
448449
}
449450
return result
450451
}
452+
453+
/// Returns the latest modification date of a unit that contains the given source file.
454+
///
455+
/// If no unit containing the given source file exists, returns `nil`.
456+
public func dateOfLatestUnitFor(filePath: String) -> Date? {
457+
let timestamp = filePath.withCString { filePathCString in
458+
indexstoredb_timestamp_of_latest_unit_for_file(impl, filePathCString)
459+
}
460+
if timestamp == 0 {
461+
return nil
462+
}
463+
return Date(timeIntervalSince1970: timestamp)
464+
}
451465
}
452466

453467
public protocol IndexStoreLibraryProvider {

Sources/IndexStoreDB/SymbolLocation.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@
1212

1313
@_implementationOnly
1414
import CIndexStoreDB
15+
import Foundation
1516

1617
public struct SymbolLocation: Equatable {
1718
public var path: String
19+
/// The date at which the unit file that contains a symbol has last been modified.
20+
public var timestamp: Date
1821
public var moduleName: String
1922
public var isSystem: Bool
2023
public var line: Int
2124
public var utf8Column: Int
2225

23-
public init(path: String, moduleName: String, isSystem: Bool = false, line: Int, utf8Column: Int) {
26+
public init(path: String, timestamp: Date, moduleName: String, isSystem: Bool = false, line: Int, utf8Column: Int) {
2427
self.path = path
28+
self.timestamp = timestamp
2529
self.moduleName = moduleName
2630
self.isSystem = isSystem
2731
self.line = line
@@ -47,6 +51,7 @@ extension SymbolLocation: CustomStringConvertible {
4751
extension SymbolLocation {
4852
internal init(_ loc: indexstoredb_symbol_location_t) {
4953
path = String(cString: indexstoredb_symbol_location_path(loc))
54+
timestamp = Date(timeIntervalSince1970: indexstoredb_symbol_location_timestamp(loc))
5055
moduleName = String(cString: indexstoredb_symbol_location_module_name(loc))
5156
isSystem = indexstoredb_symbol_location_is_system(loc)
5257
line = Int(indexstoredb_symbol_location_line(loc))

include/CIndexStoreDB/CIndexStoreDB.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,12 @@ INDEXSTOREDB_PUBLIC
375375
const char * _Nonnull
376376
indexstoredb_symbol_location_path(_Nonnull indexstoredb_symbol_location_t);
377377

378+
/// Returns a Unix timestamp (seconds since 1/1/1970) at which the unit file that contains a symbol has last been
379+
/// modified.
380+
INDEXSTOREDB_PUBLIC
381+
double
382+
indexstoredb_symbol_location_timestamp(_Nonnull indexstoredb_symbol_location_t loc);
383+
378384
/// Returns the module name of the given symbol location.
379385
///
380386
/// The string has the same lifetime as the \c indexstoredb_symbol_location_t.
@@ -571,6 +577,14 @@ indexstoredb_index_unit_tests(
571577
_Nonnull indexstoredb_symbol_occurrence_receiver_t receiver
572578
);
573579

580+
/// Returns a Unix timestamp (seconds since 1/1/1970) of the latest unit that contains the given source file.
581+
///
582+
/// If no unit containing the given source file exists, returns 0.
583+
INDEXSTOREDB_PUBLIC double
584+
indexstoredb_timestamp_of_latest_unit_for_file(
585+
_Nonnull indexstoredb_index_t index,
586+
const char *_Nonnull fileName
587+
);
574588

575589
INDEXSTOREDB_END_DECLS
576590

include/IndexStoreDB/Index/IndexSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ class INDEXSTOREDB_EXPORT IndexSystem {
177177
/// \returns `false` if the receiver returned `false` to stop receiving symbols, `true` otherwise.
178178
bool foreachUnitTestSymbol(function_ref<bool(SymbolOccurrenceRef Occur)> receiver);
179179

180+
/// Returns the latest modification date of a unit that contains the given source file.
181+
///
182+
/// If no unit containing the given source file exists, returns `None`.
183+
llvm::Optional<llvm::sys::TimePoint<>> timestampOfLatestUnitForFile(StringRef filePath);
180184
private:
181185
IndexSystem(void *Impl) : Impl(Impl) {}
182186

include/IndexStoreDB/Index/SymbolIndex.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "IndexStoreDB/Support/LLVM.h"
1717
#include "llvm/ADT/OptionSet.h"
18+
#include "llvm/Support/Chrono.h"
1819
#include <memory>
1920

2021
namespace indexstore {
@@ -101,6 +102,11 @@ class SymbolIndex {
101102
///
102103
/// \returns `false` if the receiver returned `false` to stop receiving symbols, `true` otherwise.
103104
bool foreachUnitTestSymbol(function_ref<bool(SymbolOccurrenceRef Occur)> receiver);
105+
106+
/// Returns the latest modification date of a unit that contains the given source file.
107+
///
108+
/// If no unit containing the given source file exists, returns `None`.
109+
llvm::Optional<llvm::sys::TimePoint<>> timestampOfLatestUnitForFile(CanonicalFilePathRef filePath);
104110
private:
105111
void *Impl; // A SymbolIndexImpl.
106112
};

lib/CIndexStoreDB/CIndexStoreDB.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,17 @@ indexstoredb_symbol_location_path(indexstoredb_symbol_location_t loc) {
445445
return obj->getPath().getPathString().c_str();
446446
}
447447

448+
double
449+
indexstoredb_symbol_location_timestamp(indexstoredb_symbol_location_t loc) {
450+
auto obj = (SymbolLocation *)loc;
451+
// Up until C++20 the reference date of time_since_epoch is undefined but according to
452+
// https://en.cppreference.com/w/cpp/chrono/system_clock most implementations use Unix Time.
453+
// Since C++20, system_clock is defined to measure time since 1/1/1970.
454+
// We rely on `time_since_epoch` always returning the nanoseconds since 1/1/1970.
455+
auto nanosecondsSinceEpoch = obj->getPath().getModificationTime().time_since_epoch().count();
456+
return static_cast<double>(nanosecondsSinceEpoch) / 1000 / 1000 / 1000;
457+
}
458+
448459
const char *
449460
indexstoredb_symbol_location_module_name(indexstoredb_symbol_location_t loc) {
450461
auto obj = (SymbolLocation *)loc;
@@ -657,4 +668,21 @@ indexstoredb_index_unit_tests(
657668
});
658669
}
659670

671+
INDEXSTOREDB_PUBLIC double
672+
indexstoredb_timestamp_of_latest_unit_for_file(
673+
_Nonnull indexstoredb_index_t index,
674+
const char *_Nonnull fileName
675+
) {
676+
auto obj = (Object<std::shared_ptr<IndexSystem>> *)index;
677+
llvm::Optional<llvm::sys::TimePoint<>> timePoint = obj->value->timestampOfLatestUnitForFile(fileName);
678+
if (timePoint) {
679+
// Up until C++20 the reference date of time_since_epoch is undefined but according to
680+
// https://en.cppreference.com/w/cpp/chrono/system_clock most implementations use Unix Time.
681+
// Since C++20, system_clock is defined to measure time since 1/1/1970.
682+
// We rely on `time_since_epoch` always returning the nanoseconds since 1/1/1970.
683+
return timePoint->time_since_epoch().count();
684+
}
685+
return 0;
686+
}
687+
660688
ObjectBase::~ObjectBase() {}

lib/Index/IndexSystem.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,11 @@ class IndexSystemImpl {
234234
///
235235
/// \returns `false` if the receiver returned `false` to stop receiving symbols, `true` otherwise.
236236
bool foreachUnitTestSymbol(function_ref<bool(SymbolOccurrenceRef Occur)> receiver);
237+
238+
/// Returns the latest modification date of a unit that contains the given source file.
239+
///
240+
/// If no unit containing the given source file exists, returns `None`.
241+
llvm::Optional<llvm::sys::TimePoint<>> timestampOfLatestUnitForFile(StringRef filePath);
237242
};
238243

239244
} // anonymous namespace
@@ -628,6 +633,11 @@ bool IndexSystemImpl::foreachUnitTestSymbol(function_ref<bool(SymbolOccurrenceRe
628633
return SymIndex->foreachUnitTestSymbol(std::move(receiver));
629634
}
630635

636+
llvm::Optional<llvm::sys::TimePoint<>> IndexSystemImpl::timestampOfLatestUnitForFile(StringRef filePath) {
637+
auto canonFilePath = PathIndex->getCanonicalPath(filePath);
638+
return SymIndex->timestampOfLatestUnitForFile(canonFilePath);
639+
}
640+
631641
//===----------------------------------------------------------------------===//
632642
// IndexSystem
633643
//===----------------------------------------------------------------------===//
@@ -824,3 +834,7 @@ bool IndexSystem::foreachUnitTestSymbolReferencedByMainFiles(
824834
bool IndexSystem::foreachUnitTestSymbol(function_ref<bool(SymbolOccurrenceRef Occur)> receiver) {
825835
return IMPL->foreachUnitTestSymbol(std::move(receiver));
826836
}
837+
838+
llvm::Optional<llvm::sys::TimePoint<>> IndexSystem::timestampOfLatestUnitForFile(StringRef filePath) {
839+
return IMPL->timestampOfLatestUnitForFile(filePath);
840+
}

lib/Index/SymbolIndex.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ class SymbolIndexImpl {
9999
/// \returns `false` if the receiver returned `false` to stop receiving symbols, `true` otherwise.
100100
bool foreachUnitTestSymbol(function_ref<bool(SymbolOccurrenceRef Occur)> receiver);
101101

102+
/// Returns the latest modification date of a unit that contains the given source file.
103+
///
104+
/// If no unit containing the given source file exists, returns `None`.
105+
llvm::Optional<sys::TimePoint<>> timestampOfLatestUnitForFile(CanonicalFilePathRef filePath);
106+
102107
private:
103108
/// Returns all the providers in the index that contain test cases and satisfy `unitFilter`.
104109
std::vector<SymbolDataProviderRef> providersContainingTestCases(ReadTransaction &reader, function_ref<bool(const UnitInfo &)> unitFilter);
@@ -597,6 +602,26 @@ bool SymbolIndexImpl::foreachUnitTestSymbolOccurrence(const std::vector<SymbolDa
597602
return true;
598603
}
599604

605+
llvm::Optional<sys::TimePoint<>> SymbolIndexImpl::timestampOfLatestUnitForFile(CanonicalFilePathRef filePath) {
606+
llvm::Optional<sys::TimePoint<>> result;
607+
608+
ReadTransaction reader(DBase);
609+
IDCode filePathCode = reader.getFilePathCode(filePath);
610+
reader.foreachUnitContainingFile(filePathCode, [&](ArrayRef<IDCode> idCodes) -> bool {
611+
for (IDCode idCode : idCodes) {
612+
UnitInfo unitInfo = reader.getUnitInfo(idCode);
613+
if (!result) {
614+
result = unitInfo.ModTime;
615+
} else if (*result < unitInfo.ModTime) {
616+
result = unitInfo.ModTime;
617+
}
618+
}
619+
return true;
620+
});
621+
return result;
622+
}
623+
624+
600625
//===----------------------------------------------------------------------===//
601626
// SymbolIndex
602627
//===----------------------------------------------------------------------===//
@@ -696,3 +721,7 @@ bool SymbolIndex::foreachUnitTestSymbolReferencedByMainFiles(
696721
bool SymbolIndex::foreachUnitTestSymbol(function_ref<bool(SymbolOccurrenceRef Occur)> receiver) {
697722
return IMPL->foreachUnitTestSymbol(std::move(receiver));
698723
}
724+
725+
llvm::Optional<llvm::sys::TimePoint<>> SymbolIndex::timestampOfLatestUnitForFile(CanonicalFilePathRef filePath) {
726+
return IMPL->timestampOfLatestUnitForFile(filePath);
727+
}

0 commit comments

Comments
 (0)