## Summary - Add `scan_module_decl()` — a lightweight preprocessor-based fallback that resolves module declarations inside `#if`/`#ifdef` conditionals. When `scan()` detects `need_preprocess=true`, this function runs clang's preprocessor to evaluate conditions and extract the actual module name. It stops lexing as soon as the module declaration is found, making it much cheaper than `scan_precise()`. - Integrate the fallback into `scan_dependency_graph()` for wave 0 source files, so conditional module declarations (e.g. `#ifdef USE_MODULES / export module M; / #endif`) are correctly registered in the dependency graph. - Add comprehensive test cases covering all C++20 module declaration forms from cppreference, including `scan_module_decl()` tests for conditional resolution and `scan_precise()` tests for module import semantics. ## Test plan - [x] All 310 unit tests pass (0 failures, 9 skipped) - [x] `scan()` tests cover: primary interface, implementation, dotted names, partitions, GMF, conditional module declarations, private module fragment - [x] `scan_module_decl()` tests cover: basic, conditional with `-D`, conditional with `#if` expression, GMF with conditional, implementation unit, dotted name, partition, no-module file - [x] `scan_precise()` tests cover: named import, multiple imports, dotted import, partition import, export-import, export-import partition, implementation import, GMF with import, mixed includes/imports, no-module file 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved detection of module declarations hidden by conditional compilation via a lightweight fallback scan. Resolved module vs. interface classification is cached to avoid repeated work and is used consistently in dependency mapping. * Better handling and classification of module imports, partitions, and global-fragment includes when building module relationships. * **Tests** * Added comprehensive unit tests covering module declaration extraction, fallback resolution under preprocessor guards, imports, partitions, includes, and macro-driven cases. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
50 lines
1.6 KiB
C++
50 lines
1.6 KiB
C++
#pragma once
|
|
|
|
#include "test/test.h"
|
|
#include "syntax/scan.h"
|
|
|
|
namespace clice::testing {
|
|
|
|
/// Helper that sets up a TestVFS with a main file and optional extra files,
|
|
/// then calls the given scan function with standard C++20 arguments.
|
|
struct ModuleScanFixture {
|
|
llvm::IntrusiveRefCntPtr<TestVFS> vfs = llvm::makeIntrusiveRefCnt<TestVFS>();
|
|
std::string main_path;
|
|
std::vector<const char*> args;
|
|
|
|
// Non-copyable/non-movable: args stores raw pointers (main_path.c_str())
|
|
// that would dangle after copy/move.
|
|
ModuleScanFixture(const ModuleScanFixture&) = delete;
|
|
ModuleScanFixture& operator=(const ModuleScanFixture&) = delete;
|
|
ModuleScanFixture(ModuleScanFixture&&) = delete;
|
|
ModuleScanFixture& operator=(ModuleScanFixture&&) = delete;
|
|
|
|
/// Create fixture with main file content and optional extra defines.
|
|
ModuleScanFixture(llvm::StringRef filename,
|
|
llvm::StringRef content,
|
|
std::initializer_list<const char*> extra_args = {}) {
|
|
main_path = TestVFS::path(filename);
|
|
vfs->add(filename, content);
|
|
args.push_back("clang++");
|
|
args.push_back("-std=c++20");
|
|
for(auto a: extra_args) {
|
|
args.push_back(a);
|
|
}
|
|
args.push_back(main_path.c_str());
|
|
}
|
|
|
|
void add_file(llvm::StringRef name, llvm::StringRef content = "") {
|
|
vfs->add(name, content);
|
|
}
|
|
|
|
ScanResult decl() {
|
|
return scan_module_decl(args, TestVFS::root(), {}, nullptr, vfs);
|
|
}
|
|
|
|
ScanResult precise() {
|
|
return scan_precise(args, TestVFS::root(), {}, nullptr, vfs);
|
|
}
|
|
};
|
|
|
|
} // namespace clice::testing
|