Skip to content

Commit bc32261

Browse files
fix: invalid module units
1 parent caec233 commit bc32261

File tree

15 files changed

+542
-144
lines changed

15 files changed

+542
-144
lines changed

.github/workflows/generate-docs.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ jobs:
3232
restore-keys: |
3333
Windows-sccache-
3434
35+
- name: Start sccache
36+
run: sccache --start-server
37+
3538
- name: Build
3639
run: pixi run build
3740

@@ -55,5 +58,4 @@ jobs:
5558
retention-days: 30
5659

5760
- name: Stop sccache
58-
if: always()
59-
run: pixi run -- sccache --stop-server 2>$null
61+
run: sccache --stop-server

cmake/toolchain.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ cmake_minimum_required(VERSION 3.30)
33
set(CMAKE_C_COMPILER clang CACHE STRING "")
44
set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")
55

6+
find_program(CLANG_SCAN_DEPS_PATH "clang-scan-deps")
7+
if(CLANG_SCAN_DEPS_PATH)
8+
set(CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS "${CLANG_SCAN_DEPS_PATH}" CACHE FILEPATH "")
9+
endif()
10+
611
find_program(LLVM_AR_PATH "llvm-ar")
712
if(LLVM_AR_PATH)
813
set(CMAKE_AR "${LLVM_AR_PATH}" CACHE FILEPATH "")

src/CMakeLists.txt

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,9 @@ file(GLOB_RECURSE CLORE_MODULE_SOURCES CONFIGURE_DEPENDS
55
"${CMAKE_CURRENT_SOURCE_DIR}/support/*.cppm"
66
)
77

8-
# ── locate clang-scan-deps (required for C++20 module compilation) ───
9-
find_program(CLANG_SCAN_DEPS_EXE
10-
NAMES clang-scan-deps
11-
HINTS
12-
"${CMAKE_CXX_COMPILER}/../"
13-
"$ENV{CONDA_PREFIX}/Library/bin"
14-
"$ENV{CONDA_PREFIX}/bin"
15-
)
16-
if(CLANG_SCAN_DEPS_EXE)
17-
set(CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS "${CLANG_SCAN_DEPS_EXE}" CACHE FILEPATH "" FORCE)
18-
message(STATUS "Found clang-scan-deps: ${CLANG_SCAN_DEPS_EXE}")
8+
# ── report clang-scan-deps configuration for C++20 module compilation ───
9+
if(CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS)
10+
message(STATUS "Found clang-scan-deps: ${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}")
1911
else()
2012
message(STATUS "clang-scan-deps not found; will rely on CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS cache")
2113
endif()

src/extract/ast.cppm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module;
44
#include <cstdint>
55
#include <expected>
66
#include <format>
7+
#include <memory>
78
#include <string>
89
#include <unordered_set>
910
#include <vector>

src/extract/compdb.cppm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module;
22

3+
#include <algorithm>
34
#include <expected>
45
#include <filesystem>
56
#include <format>

src/extract/extract.cppm

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -287,21 +287,22 @@ auto rebuild_model_indexes(const config::TaskConfig& config, ProjectModel& model
287287

288288
/// Populate module information from scan cache into the project model.
289289
auto build_module_info(ProjectModel& model, const ScanCache& scan_cache) -> void {
290+
namespace fs = std::filesystem;
291+
290292
for(auto& [file_path, scan_result] : scan_cache) {
291293
if(scan_result.module_name.empty()) continue;
292294

293295
model.uses_modules = true;
294296

295-
auto& mod_unit = model.modules[scan_result.module_name];
297+
auto source_file = fs::path(file_path).lexically_normal().generic_string();
298+
auto& mod_unit = model.modules[source_file];
296299
mod_unit.name = scan_result.module_name;
297300
mod_unit.is_interface = scan_result.is_interface_unit;
298-
mod_unit.source_file = file_path;
301+
mod_unit.source_file = source_file;
299302
mod_unit.imports = scan_result.module_imports;
300303

301304
// Associate symbols from that file to this module unit
302-
namespace fs = std::filesystem;
303-
auto generic_path = fs::path(file_path).generic_string();
304-
auto file_it = model.files.find(generic_path);
305+
auto file_it = model.files.find(source_file);
305306
if(file_it != model.files.end()) {
306307
mod_unit.symbols = file_it->second.symbols;
307308
}
@@ -398,38 +399,29 @@ auto extract_project(const config::TaskConfig& config)
398399
current_file_info.path = normalized;
399400
std::size_t includes_kept = 0;
400401

401-
if(cache_it != scan_cache.end()) {
402-
for(auto& inc : cache_it->second.includes) {
403-
namespace fs = std::filesystem;
404-
auto inc_path = fs::path(inc.path);
405-
if(inc_path.is_relative()) {
406-
inc_path = fs::path(entry.directory) / inc_path;
407-
}
408-
inc_path = inc_path.lexically_normal();
409-
if(matches_filter(inc_path.string(), config.filter, filter_root)) {
410-
append_unique(current_file_info.includes, inc_path.generic_string());
411-
++includes_kept;
412-
}
413-
}
414-
} else {
402+
if(cache_it == scan_cache.end()) {
415403
logging::warn("scan cache miss for {}, re-scanning", entry.file);
416404
auto scan_result = scan_file(entry);
417405
if(!scan_result.has_value()) {
418406
return std::unexpected(ExtractError{
419407
.message = std::format("failed to scan includes for {}: {}",
420408
entry.file, scan_result.error().message)});
421409
}
422-
for(auto& inc : scan_result->includes) {
423-
namespace fs = std::filesystem;
424-
auto inc_path = fs::path(inc.path);
425-
if(inc_path.is_relative()) {
426-
inc_path = fs::path(entry.directory) / inc_path;
427-
}
428-
inc_path = inc_path.lexically_normal();
429-
if(matches_filter(inc_path.string(), config.filter, filter_root)) {
430-
append_unique(current_file_info.includes, inc_path.generic_string());
431-
++includes_kept;
432-
}
410+
411+
auto [rescanned_it, _] = scan_cache.insert_or_assign(cache_key, std::move(*scan_result));
412+
cache_it = rescanned_it;
413+
}
414+
415+
for(auto& inc : cache_it->second.includes) {
416+
namespace fs = std::filesystem;
417+
auto inc_path = fs::path(inc.path);
418+
if(inc_path.is_relative()) {
419+
inc_path = fs::path(entry.directory) / inc_path;
420+
}
421+
inc_path = inc_path.lexically_normal();
422+
if(matches_filter(inc_path.string(), config.filter, filter_root)) {
423+
append_unique(current_file_info.includes, inc_path.generic_string());
424+
++includes_kept;
433425
}
434426
}
435427

@@ -510,9 +502,9 @@ auto extract_project(const config::TaskConfig& config)
510502
build_module_info(model, scan_cache);
511503
if(model.uses_modules) {
512504
logging::info("detected {} module units", model.modules.size());
513-
for(auto& [name, mod] : model.modules) {
505+
for(auto& [source_file, mod] : model.modules) {
514506
logging::info(" module '{}' (interface={}) from {}",
515-
name, mod.is_interface, mod.source_file);
507+
mod.name, mod.is_interface, source_file);
516508
}
517509
}
518510

src/extract/model.cppm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ struct ProjectModel {
8686

8787
std::vector<std::string> file_order;
8888

89-
/// Module units indexed by module name (e.g. "foo", "foo:bar").
89+
/// Module units indexed by normalized source file path.
9090
std::unordered_map<std::string, ModuleUnit> modules;
9191

9292
/// True if the project uses C++20 modules (at least one module declaration found).

src/extract/scan.cppm

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module;
55
#include <filesystem>
66
#include <format>
77
#include <fstream>
8+
#include <memory>
89
#include <queue>
910
#include <string>
1011
#include <string_view>
@@ -82,6 +83,31 @@ namespace clore::extract {
8283

8384
namespace {
8485

86+
auto append_unique_import(ScanResult& result, std::string import_name) -> void {
87+
if(std::ranges::find(result.module_imports, import_name) != result.module_imports.end()) {
88+
return;
89+
}
90+
result.module_imports.push_back(std::move(import_name));
91+
}
92+
93+
auto normalize_partition_import(std::string_view current_module_name,
94+
std::string import_name) -> std::string {
95+
if(import_name.starts_with(':') && !current_module_name.empty()) {
96+
auto main_name = current_module_name;
97+
if(auto colon_pos = current_module_name.find(':'); colon_pos != std::string::npos) {
98+
main_name = current_module_name.substr(0, colon_pos);
99+
}
100+
101+
std::string normalized;
102+
normalized.reserve(main_name.size() + import_name.size());
103+
normalized += main_name;
104+
normalized += import_name;
105+
return normalized;
106+
}
107+
108+
return import_name;
109+
}
110+
85111
class ScanPPCallbacks : public clang::PPCallbacks {
86112
public:
87113
ScanResult& result;
@@ -187,7 +213,9 @@ auto scan_module_decl(std::string_view file_content, ScanResult& result) -> void
187213
}
188214

189215
if(!import_name.empty()) {
190-
result.module_imports.push_back(std::move(import_name));
216+
append_unique_import(result,
217+
normalize_partition_import(result.module_name,
218+
std::move(import_name)));
191219
}
192220
}
193221
}

src/extract/symbol.cppm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module;
22

3+
#include <compare>
34
#include <cstdint>
45
#include <functional>
56
#include <string>

0 commit comments

Comments
 (0)