Skip to content

Commit 5bef313

Browse files
committed
Cache and reuse Clang files.
Don't rely on Clang's own caches for this. Avoids the need to touch FileManager.
1 parent e48e4db commit 5bef313

File tree

2 files changed

+54
-33
lines changed

2 files changed

+54
-33
lines changed

toolchain/check/context.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ class Context {
157157
return import_ir_constant_values_;
158158
}
159159

160+
auto cpp_carbon_file_locations()
161+
-> llvm::SmallVector<clang::SourceLocation, 0>& {
162+
return cpp_carbon_file_locations_;
163+
}
164+
160165
auto definitions_required_by_decl() -> llvm::SmallVector<SemIR::InstId>& {
161166
return definitions_required_by_decl_;
162167
}
@@ -384,6 +389,10 @@ class Context {
384389
// Inline 0 elements because it's expected to require heap allocation.
385390
llvm::SmallVector<SemIR::ConstantValueStore, 0> import_ir_constant_values_;
386391

392+
// Per-Carbon-file start locations for corresponding Clang source buffers.
393+
// Owned and managed by code in cpp/location.cpp.
394+
llvm::SmallVector<clang::SourceLocation, 0> cpp_carbon_file_locations_;
395+
387396
// Declaration instructions of entities that should have definitions by the
388397
// end of the current source file.
389398
llvm::SmallVector<SemIR::InstId> definitions_required_by_decl_;

toolchain/check/cpp/location.cpp

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,49 @@
99

1010
namespace Carbon::Check {
1111

12-
static auto GetFile(Context& context, SemIR::CheckIRId ir_id)
13-
-> const SemIR::File* {
14-
if (ir_id == context.sem_ir().check_ir_id()) {
15-
// Common case: the IR is the current file.
16-
return &context.sem_ir();
17-
}
12+
namespace {
13+
struct FileInfo {
14+
const SemIR::File* sem_ir;
15+
clang::SourceLocation start_loc;
16+
};
17+
} // namespace
18+
19+
// Map a CheckIRId into information about the corresponding file in both SemIR
20+
// and Clang's source manager.
21+
static auto GetFileInfo(Context& context, SemIR::CheckIRId ir_id) -> FileInfo {
22+
const SemIR::File* sem_ir = &context.sem_ir();
23+
unsigned file_index = 0;
1824

1925
// If the file is imported, locate it in our imports map.
20-
auto import_id = context.check_ir_map().Get(ir_id);
21-
CARBON_CHECK(import_id.has_value());
22-
return context.import_irs().Get(import_id).sem_ir;
26+
if (ir_id != context.sem_ir().check_ir_id()) {
27+
auto import_id = context.check_ir_map().Get(ir_id);
28+
CARBON_CHECK(import_id.has_value());
29+
file_index = import_id.index + 1;
30+
31+
sem_ir = context.import_irs().Get(import_id).sem_ir;
32+
CARBON_CHECK(sem_ir, "Node location in nonexistent IR");
33+
}
34+
35+
// If we've seen this file before, reuse the same FileID.
36+
auto& file_start_locs = context.cpp_carbon_file_locations();
37+
if (file_start_locs.size() <= file_index) {
38+
file_start_locs.resize(file_index + 1);
39+
}
40+
if (file_start_locs[file_index].isValid()) {
41+
return {.sem_ir = sem_ir, .start_loc = file_start_locs[file_index]};
42+
}
43+
44+
// We've not seen this file before. Create a corresponding virtual file in
45+
// Clang's source manager.
46+
// TODO: Consider recreating the complete import path instead of only the
47+
// final entry.
48+
const auto& source = sem_ir->parse_tree().tokens().source();
49+
auto& src_mgr = context.ast_context().getSourceManager();
50+
auto file_id = src_mgr.createFileID(
51+
llvm::MemoryBufferRef(source.text(), source.filename()));
52+
auto file_start_loc = src_mgr.getLocForStartOfFile(file_id);
53+
file_start_locs[file_index] = file_start_loc;
54+
return {.sem_ir = sem_ir, .start_loc = file_start_loc};
2355
}
2456

2557
auto GetCppLocation(Context& context, SemIR::LocId loc_id)
@@ -37,34 +69,14 @@ auto GetCppLocation(Context& context, SemIR::LocId loc_id)
3769
absolute_node_ids.back().clang_source_loc_id());
3870
}
3971

40-
// This is a location in Carbon code; decompose it so we can map it into a
41-
// Clang location.
42-
// TODO: Consider recreating the complete import path instead of only the
43-
// final entry.
72+
// This is a location in Carbon code; get or create a corresponding file in
73+
// Clang and build a corresponding location.
4474
auto absolute_node_id = absolute_node_ids.back();
45-
const auto* ir = GetFile(context, absolute_node_id.check_ir_id());
46-
CARBON_CHECK(ir, "Node location points at nonexistent IR");
75+
auto [ir, start_loc] = GetFileInfo(context, absolute_node_id.check_ir_id());
4776
const auto& tree = ir->parse_tree();
48-
const auto& source = tree.tokens().source();
4977
auto offset =
5078
tree.tokens().GetByteOffset(tree.node_token(absolute_node_id.node_id()));
51-
52-
// Get or create a corresponding Clang file.
53-
// TODO: Consider caching a mapping from Carbon ImportIRIds to Clang
54-
// start-of-file SourceLocations.
55-
auto& src_mgr = context.ast_context().getSourceManager();
56-
auto file = src_mgr.getFileManager().getOptionalFileRef(source.filename());
57-
if (!file) {
58-
file = src_mgr.getFileManager().getVirtualFileRef(
59-
source.filename(), source.text().size(), /*ModificationTime=*/0);
60-
}
61-
src_mgr.overrideFileContents(
62-
*file, llvm::MemoryBufferRef(source.text(), source.filename()));
63-
64-
// Build a corresponding location.
65-
auto file_id = src_mgr.getOrCreateFileID(
66-
*file, clang::SrcMgr::CharacteristicKind::C_User);
67-
return src_mgr.getLocForStartOfFile(file_id).getLocWithOffset(offset);
79+
return start_loc.getLocWithOffset(offset);
6880
}
6981

7082
} // namespace Carbon::Check

0 commit comments

Comments
 (0)