Skip to content

Commit 4dfc125

Browse files
authored
Merge pull request #94 from akyrtzi/unit-includes-api
[Index] Add APIs to provide the recorded #includes of a unit file
2 parents 6e910e3 + 2961718 commit 4dfc125

File tree

12 files changed

+184
-30
lines changed

12 files changed

+184
-30
lines changed

Sources/IndexStoreDB/IndexStoreDB.swift

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ public final class IndexStoreDB {
195195
@discardableResult
196196
public func forEachMainFileContainingFile(path: String, crossLanguage: Bool, body: @escaping (String) -> Bool) -> Bool {
197197
let fromSwift = path.hasSuffix(".swift")
198-
return indexstoredb_index_main_files_containing_file(impl, path) { mainFile in
199-
let mainFileStr = String(cString: mainFile)
198+
return indexstoredb_index_units_containing_file(impl, path) { unit in
199+
let mainFileStr = String(cString: indexstoredb_unit_info_main_file_path(unit))
200200
let toSwift = mainFileStr.hasSuffix(".swift")
201201
if !crossLanguage && fromSwift != toSwift {
202202
return true // continue
@@ -214,6 +214,59 @@ public final class IndexStoreDB {
214214
return result
215215
}
216216

217+
@discardableResult
218+
public func forEachUnitNameContainingFile(path: String, body: @escaping (String) -> Bool) -> Bool {
219+
return indexstoredb_index_units_containing_file(impl, path) { unit in
220+
let unitName = String(cString: indexstoredb_unit_info_unit_name(unit))
221+
return body(unitName)
222+
}
223+
}
224+
225+
public func unitNamesContainingFile(path: String) -> [String] {
226+
var result: [String] = []
227+
forEachUnitNameContainingFile(path: path) { unitName in
228+
result.append(unitName)
229+
return true
230+
}
231+
return result
232+
}
233+
234+
/// A recorded header `#include` from a unit file.
235+
public struct UnitIncludeEntry: Equatable {
236+
/// The path where the `#include` was added.
237+
public let sourcePath: String
238+
/// The path that the `#include` resolved to.
239+
public let targetPath: String
240+
/// the line where the `#include` was added.
241+
public let line: Int
242+
243+
public init(sourcePath: String, targetPath: String, line: Int) {
244+
self.sourcePath = sourcePath
245+
self.targetPath = targetPath
246+
self.line = line
247+
}
248+
}
249+
250+
/// Iterates over recorded `#include`s of a unit.
251+
@discardableResult
252+
public func forEachIncludeOfUnit(unitName: String, body: @escaping (UnitIncludeEntry) -> Bool) -> Bool {
253+
return indexstoredb_index_includes_of_unit(impl, unitName) { sourcePath, targetPath, line in
254+
let sourcePathStr = String(cString: sourcePath)
255+
let targetPathStr = String(cString: targetPath)
256+
return body(UnitIncludeEntry(sourcePath: sourcePathStr, targetPath: targetPathStr, line: line))
257+
}
258+
}
259+
260+
/// Returns the recorded `#include`s of a unit.
261+
public func includesOfUnit(unitName: String) -> [UnitIncludeEntry] {
262+
var result: [UnitIncludeEntry] = []
263+
forEachIncludeOfUnit(unitName: unitName) { entry in
264+
result.append(entry)
265+
return true
266+
}
267+
return result
268+
}
269+
217270
/// Iterates over the name of every symbol in the index.
218271
///
219272
/// - Parameter body: A closure to be called for each symbol. The closure should return true to

Tests/INPUTS/MainFiles/main1.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#include "shared.h"
2-
#include "uniq1.h"
1+
#include "shared.h" /*include_main1_shared*/
2+
#include "uniq1.h" /*include_main1_uniq1*/
33

44
void main1(void) {
55
/*main1*/

Tests/IndexStoreDBTests/IndexTests.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,26 @@ final class IndexTests: XCTestCase {
280280
XCTAssertEqual(mainFiles(unknown, false), [])
281281
}
282282

283+
func testUnitIncludes() throws {
284+
guard let ws = try staticTibsTestWorkspace(name: "MainFiles") else { return }
285+
try ws.buildAndIndex()
286+
let index = ws.index
287+
288+
let main1 = ws.testLoc("main1").url.path
289+
let uniq1 = ws.testLoc("uniq1").url.path
290+
let shared = ws.testLoc("shared").url.path
291+
292+
let units = index.unitNamesContainingFile(path: main1)
293+
XCTAssertEqual(units.count, 1)
294+
let main1Unit = try XCTUnwrap(units.first)
295+
296+
let includes = index.includesOfUnit(unitName: main1Unit)
297+
XCTAssertEqual(includes, [
298+
IndexStoreDB.UnitIncludeEntry(sourcePath: main1, targetPath: shared, line: ws.testLoc("include_main1_shared").line),
299+
IndexStoreDB.UnitIncludeEntry(sourcePath: main1, targetPath: uniq1, line: ws.testLoc("include_main1_uniq1").line),
300+
])
301+
}
302+
283303
func testAllSymbolNames() throws {
284304
guard let ws = try staticTibsTestWorkspace(name: "proj1") else { return }
285305
try ws.buildAndIndex()

Tests/IndexStoreDBTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ extension IndexTests {
2424
("testMainFilesContainingFile", testMainFilesContainingFile),
2525
("testMixedLangTarget", testMixedLangTarget),
2626
("testSwiftModules", testSwiftModules),
27+
("testUnitIncludes", testUnitIncludes),
2728
("testWaitUntilDoneInitializing", testWaitUntilDoneInitializing),
2829
]
2930
}

include/CIndexStoreDB/CIndexStoreDB.h

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ typedef void *indexstoredb_symbol_occurrence_t;
5757
typedef void *indexstoredb_error_t;
5858
typedef void *indexstoredb_symbol_location_t;
5959
typedef void *indexstoredb_symbol_relation_t;
60+
typedef void *indexstoredb_unit_info_t;
6061

6162
typedef enum {
6263
INDEXSTOREDB_SYMBOL_ROLE_DECLARATION = 1 << 0,
@@ -135,7 +136,10 @@ typedef bool(^indexstoredb_symbol_name_receiver)(const char *_Nonnull);
135136
typedef void(^indexstoredb_delegate_event_receiver_t)(_Nonnull indexstoredb_delegate_event_t);
136137

137138
/// Returns true to continue.
138-
typedef bool(^indexstoredb_path_receiver)(const char *_Nonnull);
139+
typedef bool(^indexstoredb_unit_info_receiver)(_Nonnull indexstoredb_unit_info_t);
140+
141+
/// Returns true to continue.
142+
typedef bool(^indexstoredb_unit_includes_receiver)(const char *_Nonnull sourcePath, const char *_Nonnull targetPath, size_t line);
139143

140144
/// Creates an index for the given raw index data in \p storePath.
141145
///
@@ -352,20 +356,41 @@ indexstoredb_symbol_occurrence_relations(_Nonnull indexstoredb_symbol_occurrence
352356
INDEXSTOREDB_PUBLIC indexstoredb_symbol_kind_t
353357
indexstoredb_symbol_kind(_Nonnull indexstoredb_symbol_t);
354358

355-
/// Iterates over the compilation units that contain \p path and return their main file.
359+
/// Returns the main file path of a unit info object.
360+
///
361+
/// The main file is typically the one that e.g. a build system would have explicit knowledge of.
362+
INDEXSTOREDB_PUBLIC const char *_Nonnull
363+
indexstoredb_unit_info_main_file_path(_Nonnull indexstoredb_unit_info_t);
364+
365+
/// Returns the unit name of a unit info object.
366+
INDEXSTOREDB_PUBLIC const char *_Nonnull
367+
indexstoredb_unit_info_unit_name(_Nonnull indexstoredb_unit_info_t);
368+
369+
/// Iterates over the compilation units that contain \p path and return their units.
356370
///
357-
/// This can be used to find the main files that include a given header. The main file is typically
358-
/// the one that e.g. a build system would have explicit knowledge of.
371+
/// This can be used to find information for units that include a given header.
359372
///
360373
/// \param index An IndexStoreDB object which contains the symbols.
361374
/// \param path The source file to search for.
362-
/// \param receiver A function to be called for each main file path. The string pointer is only valid for
375+
/// \param receiver A function to be called for each unit. The pointer is only valid for
363376
/// the duration of the call. The function should return a true to continue iterating.
364377
INDEXSTOREDB_PUBLIC bool
365-
indexstoredb_index_main_files_containing_file(
378+
indexstoredb_index_units_containing_file(
366379
_Nonnull indexstoredb_index_t index,
367380
const char *_Nonnull path,
368-
_Nonnull indexstoredb_path_receiver receiver);
381+
_Nonnull indexstoredb_unit_info_receiver receiver);
382+
383+
/// Iterates over recorded `#include`s of a unit.
384+
///
385+
/// \param index An IndexStoreDB object which contains the symbols.
386+
/// \param unitName The unit name to search for.
387+
/// \param receiver A function to be called for each include entry. The pointers are only valid for
388+
/// the duration of the call. The function should return a true to continue iterating.
389+
INDEXSTOREDB_PUBLIC bool
390+
indexstoredb_index_includes_of_unit(
391+
_Nonnull indexstoredb_index_t index,
392+
const char *_Nonnull unitName,
393+
_Nonnull indexstoredb_unit_includes_receiver receiver);
369394

370395
INDEXSTOREDB_END_DECLS
371396

include/IndexStoreDB/Index/FilePathIndex.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ class FilePathIndex {
7272
bool foreachFileIncludedByFile(CanonicalFilePathRef sourcePath,
7373
function_ref<bool(CanonicalFilePathRef TargetPath, unsigned Line)> Receiver);
7474

75+
bool foreachIncludeOfUnit(StringRef unitName,
76+
function_ref<bool(CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)> receiver);
77+
7578
private:
7679
void *Impl; // A FileIndexImpl.
7780
};

include/IndexStoreDB/Index/IndexSystem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ class INDEXSTOREDB_EXPORT IndexSystem {
139139
bool foreachFileIncludedByFile(StringRef SourcePath,
140140
function_ref<bool(CanonicalFilePathRef TargetPath, unsigned Line)> Receiver);
141141

142+
bool foreachIncludeOfUnit(StringRef unitName,
143+
function_ref<bool(CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)> receiver);
144+
142145
/// Returns unit test class/method occurrences that are referenced from units associated with the provided output file paths.
143146
/// \returns `false` if the receiver returned `false` to stop receiving symbols, `true` otherwise.
144147
bool foreachUnitTestSymbolReferencedByOutputPaths(ArrayRef<CanonicalFilePathRef> FilePaths,

include/IndexStoreDB/Support/Path.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ namespace IndexStoreDB {
2222
class CanonicalFilePathRef;
2323

2424
class CanonicalFilePath {
25-
SmallString<128> Path;
25+
std::string Path;
2626

2727
public:
2828
CanonicalFilePath() = default;
2929
inline CanonicalFilePath(CanonicalFilePathRef CanonPath);
3030

31-
StringRef getPath() const { return Path; }
31+
const std::string &getPath() const { return Path; }
3232
bool empty() const { return Path.empty(); }
3333

3434
friend bool operator==(CanonicalFilePath LHS, CanonicalFilePath RHS) {

lib/CIndexStoreDB/CIndexStoreDB.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,14 +422,38 @@ static indexstoredb_symbol_kind_t toCSymbolKind(SymbolKind K) {
422422
}
423423
}
424424

425+
const char *
426+
indexstoredb_unit_info_main_file_path(indexstoredb_unit_info_t info) {
427+
auto obj = (const StoreUnitInfo *)info;
428+
return obj->MainFilePath.getPath().c_str();
429+
}
430+
431+
const char *
432+
indexstoredb_unit_info_unit_name(indexstoredb_unit_info_t info) {
433+
auto obj = (const StoreUnitInfo *)info;
434+
return obj->UnitName.c_str();
435+
}
436+
425437
bool
426-
indexstoredb_index_main_files_containing_file(
438+
indexstoredb_index_units_containing_file(
427439
indexstoredb_index_t index,
428440
const char *path,
429-
indexstoredb_path_receiver receiver)
441+
indexstoredb_unit_info_receiver receiver)
430442
{
431443
auto obj = (IndexStoreDBObject<std::shared_ptr<IndexSystem>> *)index;
432444
return obj->value->foreachMainUnitContainingFile(path, [&](const StoreUnitInfo &unitInfo) -> bool {
433-
return receiver(unitInfo.MainFilePath.getPath().str().c_str());
445+
return receiver((indexstoredb_unit_info_receiver)&unitInfo);
446+
});
447+
}
448+
449+
bool
450+
indexstoredb_index_includes_of_unit(
451+
indexstoredb_index_t index,
452+
const char *unitName,
453+
indexstoredb_unit_includes_receiver receiver)
454+
{
455+
auto obj = (IndexStoreDBObject<std::shared_ptr<IndexSystem>> *)index;
456+
return obj->value->foreachIncludeOfUnit(unitName, [&](CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)->bool {
457+
return receiver(sourcePath.getPath().str().c_str(), targetPath.getPath().str().c_str(), line);
434458
});
435459
}

lib/Index/FilePathIndex.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class FileIndexImpl {
7676
bool foreachFileIncludedByFile(CanonicalFilePathRef sourcePath,
7777
function_ref<bool(CanonicalFilePathRef targetPath, unsigned line)> Receiver);
7878

79+
bool foreachIncludeOfUnit(StringRef unitName,
80+
function_ref<bool(CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)> receiver);
81+
7982
bool foreachIncludeOfStoreUnitContainingFile(CanonicalFilePathRef filePath,
8083
function_ref<bool(CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)> receiver);
8184
};
@@ -223,6 +226,23 @@ bool FileIndexImpl::foreachFileIncludedByFile(CanonicalFilePathRef inputSourcePa
223226
});
224227
}
225228

229+
bool FileIndexImpl::foreachIncludeOfUnit(StringRef unitName,
230+
function_ref<bool(CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)> receiver) {
231+
std::string error;
232+
IndexUnitReader storeUnit(*IdxStore, unitName, error);
233+
if (!storeUnit.isValid())
234+
return true;
235+
StringRef workDir = storeUnit.getWorkingDirectory();
236+
return storeUnit.foreachInclude([&](IndexUnitInclude inc) -> bool {
237+
StringRef sourcePath = inc.getSourcePath();
238+
StringRef targetPath = inc.getTargetPath();
239+
unsigned line = inc.getSourceLine();
240+
CanonicalFilePath fullSourcePath = getCanonicalPath(sourcePath, workDir);
241+
CanonicalFilePath fullTargetPath = getCanonicalPath(targetPath, workDir);
242+
return receiver(fullSourcePath, fullTargetPath, line);
243+
});
244+
}
245+
226246
bool FileIndexImpl::foreachIncludeOfStoreUnitContainingFile(CanonicalFilePathRef filePath,
227247
function_ref<bool(CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)> receiver) {
228248
SmallVector<std::string, 32> allUnitNames;
@@ -241,19 +261,7 @@ bool FileIndexImpl::foreachIncludeOfStoreUnitContainingFile(CanonicalFilePathRef
241261
}
242262

243263
for (auto &unitName: allUnitNames) {
244-
std::string error;
245-
IndexUnitReader storeUnit(*IdxStore, unitName, error);
246-
if (!storeUnit.isValid())
247-
continue;
248-
StringRef workDir = storeUnit.getWorkingDirectory();
249-
bool cont = storeUnit.foreachInclude([&](IndexUnitInclude inc) -> bool {
250-
StringRef sourcePath = inc.getSourcePath();
251-
StringRef targetPath = inc.getTargetPath();
252-
unsigned line = inc.getSourceLine();
253-
CanonicalFilePath fullSourcePath = getCanonicalPath(sourcePath, workDir);
254-
CanonicalFilePath fullTargetPath = getCanonicalPath(targetPath, workDir);
255-
return receiver(fullSourcePath, fullTargetPath, line);
256-
});
264+
bool cont = foreachIncludeOfUnit(unitName, receiver);
257265
if (!cont)
258266
return false;
259267
}
@@ -314,3 +322,7 @@ bool FilePathIndex::foreachFileIncludingFile(CanonicalFilePathRef TargetPath, fu
314322
bool FilePathIndex::foreachFileIncludedByFile(CanonicalFilePathRef SourcePath, function_ref<bool (CanonicalFilePathRef, unsigned int)> Receiver) {
315323
return IMPL->foreachFileIncludedByFile(SourcePath, Receiver);
316324
}
325+
326+
bool FilePathIndex::foreachIncludeOfUnit(StringRef unitName, function_ref<bool(CanonicalFilePathRef sourcePath, CanonicalFilePathRef targetPath, unsigned line)> receiver) {
327+
return IMPL->foreachIncludeOfUnit(unitName, receiver);
328+
}

0 commit comments

Comments
 (0)