refactor: move command files to src/command/, remove scan_fuzzy (#366)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -131,8 +131,8 @@ add_custom_target(generate_flatbuffers_schema DEPENDS "${GENERATED_HEADER}")
|
||||
|
||||
# Temporary migration-only build graph.
|
||||
add_library(clice-core STATIC
|
||||
"${PROJECT_SOURCE_DIR}/src/compile/command.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/compile/toolchain.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/command/command.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/command/toolchain.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/compile/compilation.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/compile/compilation_unit.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/compile/diagnostic.cpp"
|
||||
|
||||
10
src/clice.cc
10
src/clice.cc
@@ -1,11 +1,10 @@
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <print>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "eventide/async/async.h"
|
||||
#include "eventide/deco/macro.h"
|
||||
#include "eventide/deco/runtime.h"
|
||||
#include "eventide/deco/deco.h"
|
||||
#include "eventide/ipc/peer.h"
|
||||
#include "eventide/ipc/transport.h"
|
||||
#include "server/master_server.h"
|
||||
@@ -61,10 +60,7 @@ int main(int argc, const char** argv) {
|
||||
auto& opts = result->options;
|
||||
|
||||
if(opts.help.value_or(false)) {
|
||||
auto dispatcher = deco::cli::Dispatcher<clice::Options>("clice [OPTIONS]");
|
||||
std::ostringstream oss;
|
||||
dispatcher.usage(oss, true);
|
||||
std::print("{}", oss.str());
|
||||
deco::cli::write_usage_for<clice::Options>(std::cout, "clice [OPTIONS]");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "compile/command.h"
|
||||
#include "command/command.h"
|
||||
|
||||
#include <array>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
#include "compile/driver.h"
|
||||
#include "compile/toolchain.h"
|
||||
#include "command/driver.h"
|
||||
#include "command/toolchain.h"
|
||||
#include "support/filesystem.h"
|
||||
#include "support/logging.h"
|
||||
#include "support/object_pool.h"
|
||||
@@ -252,12 +252,20 @@ struct CompilationDatabase::Impl {
|
||||
|
||||
llvm::SmallVector<const char*, 32> arguments;
|
||||
|
||||
/// FIXME: We need a better way to handle this.
|
||||
if(command.contains("cl.exe") || command.contains("clang-cl")) {
|
||||
llvm::cl::TokenizeWindowsCommandLineFull(command, saver, arguments);
|
||||
} else {
|
||||
llvm::cl::TokenizeGNUCommandLine(command, saver, arguments);
|
||||
}
|
||||
/// On Windows, always use the Windows tokenizer regardless of the compiler
|
||||
/// (MSVC, clang-cl, MinGW, etc.), because all programs are invoked through
|
||||
/// the Windows API and paths use backslashes. The GNU tokenizer treats '\'
|
||||
/// as an escape character, which corrupts Windows paths like C:\Users into
|
||||
/// C:Users.
|
||||
///
|
||||
/// Note: this does NOT affect toolchain.cpp's query_clang_toolchain(), which
|
||||
/// parses clang's -### output. That output uses shell-style escaping (\\),
|
||||
/// so the GNU tokenizer is correct there.
|
||||
#ifdef _WIN32
|
||||
llvm::cl::TokenizeWindowsCommandLineFull(command, saver, arguments);
|
||||
#else
|
||||
llvm::cl::TokenizeGNUCommandLine(command, saver, arguments);
|
||||
#endif
|
||||
|
||||
return self.save_compilation_info(file, directory, arguments);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
|
||||
#include "compile/command.h"
|
||||
#include "command/command.h"
|
||||
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "compile/toolchain.h"
|
||||
#include "command/toolchain.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "compile/compilation.h"
|
||||
|
||||
#include "compile/command.h"
|
||||
#include "command/command.h"
|
||||
#include "compile/diagnostic.h"
|
||||
#include "compile/implement.h"
|
||||
#include "semantic/ast_utility.h"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "compile/command.h"
|
||||
#include "command/command.h"
|
||||
#include "eventide/async/async.h"
|
||||
#include "eventide/ipc/lsp/protocol.h"
|
||||
#include "eventide/ipc/peer.h"
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "syntax/lexer.h"
|
||||
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Basic/FileEntry.h"
|
||||
@@ -62,11 +61,13 @@ ScanResult scan(llvm::StringRef content) {
|
||||
auto name = content.substr(tok.Offset, tok.Length);
|
||||
// Strip <> or "" delimiters.
|
||||
if(name.size() >= 2) {
|
||||
result.includes.push_back({
|
||||
std::string(name.substr(1, name.size() - 2)),
|
||||
conditional_depth > 0,
|
||||
false,
|
||||
});
|
||||
bool angled = name.front() == '<';
|
||||
ScanResult::IncludeInfo info;
|
||||
info.path = std::string(name.substr(1, name.size() - 2));
|
||||
info.conditional = conditional_depth > 0;
|
||||
info.is_angled = angled;
|
||||
info.is_include_next = dir.Kind == dds::pp_include_next;
|
||||
result.includes.push_back(std::move(info));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -118,53 +119,14 @@ ScanResult scan(llvm::StringRef content) {
|
||||
|
||||
namespace {
|
||||
|
||||
enum class ScanMode { Fuzzy, Precise };
|
||||
|
||||
/// Compute include_is_conditional from raw directives: for each pp_include
|
||||
/// (and pp_include_next, pp___include_macros, pp_import), record whether
|
||||
/// it is nested inside any conditional block.
|
||||
void compute_include_conditionals(SharedScanCache::CachedEntry& entry) {
|
||||
using namespace clang::dependency_directives_scan;
|
||||
|
||||
entry.include_is_conditional.clear();
|
||||
int cond_depth = 0;
|
||||
|
||||
for(auto& dir: entry.directives) {
|
||||
switch(dir.Kind) {
|
||||
case pp_if:
|
||||
case pp_ifdef:
|
||||
case pp_ifndef: {
|
||||
cond_depth++;
|
||||
break;
|
||||
}
|
||||
case pp_endif: {
|
||||
if(cond_depth > 0) {
|
||||
cond_depth--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case pp_include:
|
||||
case pp_include_next:
|
||||
case pp___include_macros:
|
||||
case pp_import: {
|
||||
entry.include_is_conditional.push_back(cond_depth > 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ScanDirectivesGetter : public clang::DependencyDirectivesGetter {
|
||||
public:
|
||||
ScanDirectivesGetter(ScanMode mode, SharedScanCache* cache, clang::FileManager& file_mgr) :
|
||||
mode(mode), cache(cache), file_mgr(&file_mgr) {}
|
||||
ScanDirectivesGetter(SharedScanCache* cache, clang::FileManager& file_mgr) :
|
||||
cache(cache), file_mgr(&file_mgr) {}
|
||||
|
||||
std::unique_ptr<clang::DependencyDirectivesGetter>
|
||||
cloneFor(clang::FileManager& new_file_mgr) override {
|
||||
return std::make_unique<ScanDirectivesGetter>(mode, cache, new_file_mgr);
|
||||
return std::make_unique<ScanDirectivesGetter>(cache, new_file_mgr);
|
||||
}
|
||||
|
||||
std::optional<llvm::ArrayRef<clang::dependency_directives_scan::Directive>>
|
||||
@@ -178,7 +140,7 @@ public:
|
||||
if(cache) {
|
||||
auto it = cache->entries.find(path);
|
||||
if(it != cache->entries.end()) {
|
||||
return get_directives(it->second);
|
||||
return llvm::ArrayRef(it->second.directives);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,149 +178,13 @@ public:
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
compute_include_conditionals(*entry_ptr);
|
||||
return get_directives(*entry_ptr);
|
||||
return llvm::ArrayRef(entry_ptr->directives);
|
||||
}
|
||||
|
||||
private:
|
||||
using DirectiveVec = llvm::SmallVector<clang::dependency_directives_scan::Directive>;
|
||||
|
||||
llvm::ArrayRef<clang::dependency_directives_scan::Directive>
|
||||
get_directives(SharedScanCache::CachedEntry& entry) {
|
||||
if(mode == ScanMode::Precise) {
|
||||
return entry.directives;
|
||||
}
|
||||
|
||||
// Fuzzy mode: strip #define/#undef and ALL conditional directives,
|
||||
// so every #include is processed unconditionally by the preprocessor.
|
||||
auto& slot = filtered_directives[&entry];
|
||||
if(slot && !slot->empty()) {
|
||||
return *slot;
|
||||
}
|
||||
|
||||
slot = std::make_unique<DirectiveVec>();
|
||||
|
||||
using namespace clang::dependency_directives_scan;
|
||||
for(auto& dir: entry.directives) {
|
||||
switch(dir.Kind) {
|
||||
case pp_define:
|
||||
case pp_undef:
|
||||
case pp_if:
|
||||
case pp_ifdef:
|
||||
case pp_ifndef:
|
||||
case pp_elif:
|
||||
case pp_elifdef:
|
||||
case pp_elifndef:
|
||||
case pp_else:
|
||||
case pp_endif:
|
||||
case pp_pragma_push_macro:
|
||||
case pp_pragma_pop_macro: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
slot->push_back(dir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *slot;
|
||||
}
|
||||
|
||||
ScanMode mode;
|
||||
SharedScanCache* cache;
|
||||
clang::FileManager* file_mgr;
|
||||
std::deque<SharedScanCache::CachedEntry> local_entries;
|
||||
llvm::DenseMap<SharedScanCache::CachedEntry*, std::unique_ptr<DirectiveVec>>
|
||||
filtered_directives;
|
||||
};
|
||||
|
||||
/// PPCallbacks for fuzzy mode: tracks per-file includes with conditional
|
||||
/// flags looked up from the SharedScanCache.
|
||||
class FuzzyScanPPCallbacks : public clang::PPCallbacks {
|
||||
public:
|
||||
FuzzyScanPPCallbacks(llvm::StringMap<ScanResult>& results,
|
||||
SharedScanCache& cache,
|
||||
clang::SourceManager& source_mgr) :
|
||||
results(results), cache(cache), source_mgr(source_mgr) {}
|
||||
|
||||
void FileChanged(clang::SourceLocation loc,
|
||||
FileChangeReason reason,
|
||||
clang::SrcMgr::CharacteristicKind,
|
||||
clang::FileID) override {
|
||||
if(reason == EnterFile) {
|
||||
current_file = get_file_path(source_mgr.getFileID(loc));
|
||||
}
|
||||
}
|
||||
|
||||
bool FileNotFound(llvm::StringRef file_name) override {
|
||||
// Record the not-found include and consume the include counter
|
||||
// so conditional flag correlation stays in sync.
|
||||
record_include(current_file, file_name.str(), true);
|
||||
// Return true to suppress the diagnostic and continue scanning.
|
||||
return true;
|
||||
}
|
||||
|
||||
void InclusionDirective(clang::SourceLocation hash_loc,
|
||||
const clang::Token&,
|
||||
llvm::StringRef file_name,
|
||||
bool,
|
||||
clang::CharSourceRange,
|
||||
clang::OptionalFileEntryRef file,
|
||||
llvm::StringRef,
|
||||
llvm::StringRef,
|
||||
const clang::Module*,
|
||||
bool,
|
||||
clang::SrcMgr::CharacteristicKind) override {
|
||||
// Determine which file this include is from via HashLoc.
|
||||
auto from_file = get_file_path(source_mgr.getFileID(hash_loc));
|
||||
|
||||
std::string resolved_path;
|
||||
if(file) {
|
||||
resolved_path = file->getFileEntry().tryGetRealPathName().str();
|
||||
if(resolved_path.empty()) {
|
||||
resolved_path = file->getName().str();
|
||||
}
|
||||
} else {
|
||||
resolved_path = file_name.str();
|
||||
}
|
||||
|
||||
record_include(from_file, std::move(resolved_path), !file.has_value());
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::StringRef get_file_path(clang::FileID fid) {
|
||||
auto fe = source_mgr.getFileEntryRefForID(fid);
|
||||
if(fe) {
|
||||
auto path = fe->getFileEntry().tryGetRealPathName();
|
||||
return path.empty() ? fe->getName() : path;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void record_include(llvm::StringRef from_file, std::string path, bool not_found) {
|
||||
// Look up conditional flag from cache.
|
||||
bool conditional = false;
|
||||
auto cache_it = cache.entries.find(from_file);
|
||||
if(cache_it != cache.entries.end()) {
|
||||
unsigned idx = include_counters[from_file]++;
|
||||
if(idx < cache_it->second.include_is_conditional.size()) {
|
||||
conditional = cache_it->second.include_is_conditional[idx];
|
||||
}
|
||||
}
|
||||
|
||||
results[from_file].includes.push_back({
|
||||
std::move(path),
|
||||
conditional,
|
||||
not_found,
|
||||
});
|
||||
}
|
||||
|
||||
llvm::StringMap<ScanResult>& results;
|
||||
SharedScanCache& cache;
|
||||
clang::SourceManager& source_mgr;
|
||||
llvm::StringRef current_file;
|
||||
llvm::StringMap<unsigned> include_counters;
|
||||
};
|
||||
|
||||
/// PPCallbacks for precise mode: single ScanResult with accurate
|
||||
@@ -368,9 +194,9 @@ public:
|
||||
explicit PreciseScanPPCallbacks(ScanResult& result) : result(result) {}
|
||||
|
||||
void InclusionDirective(clang::SourceLocation,
|
||||
const clang::Token&,
|
||||
const clang::Token& include_tok,
|
||||
llvm::StringRef file_name,
|
||||
bool,
|
||||
bool is_angled,
|
||||
clang::CharSourceRange,
|
||||
clang::OptionalFileEntryRef file,
|
||||
llvm::StringRef,
|
||||
@@ -386,11 +212,15 @@ public:
|
||||
resolved_path = file_name.str();
|
||||
}
|
||||
|
||||
result.includes.push_back({
|
||||
std::move(resolved_path),
|
||||
conditional_depth > 0,
|
||||
not_found,
|
||||
});
|
||||
ScanResult::IncludeInfo info;
|
||||
info.path = std::move(resolved_path);
|
||||
info.conditional = conditional_depth > 0;
|
||||
info.not_found = not_found;
|
||||
info.is_angled = is_angled;
|
||||
info.is_include_next =
|
||||
include_tok.getIdentifierInfo() &&
|
||||
include_tok.getIdentifierInfo()->getPPKeywordID() == clang::tok::pp_include_next;
|
||||
result.includes.push_back(std::move(info));
|
||||
}
|
||||
|
||||
void If(clang::SourceLocation, clang::SourceRange, ConditionValueKind) override {
|
||||
@@ -494,54 +324,6 @@ std::unique_ptr<clang::CompilerInstance>
|
||||
|
||||
} // namespace
|
||||
|
||||
llvm::StringMap<ScanResult> scan_fuzzy(llvm::ArrayRef<const char*> arguments,
|
||||
llvm::StringRef directory,
|
||||
llvm::StringRef content,
|
||||
SharedScanCache* cache,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs) {
|
||||
llvm::StringMap<ScanResult> results;
|
||||
|
||||
if(!vfs) {
|
||||
vfs = llvm::vfs::createPhysicalFileSystem();
|
||||
}
|
||||
|
||||
auto instance = create_scan_instance(arguments, directory, content, vfs);
|
||||
if(!instance) {
|
||||
return results;
|
||||
}
|
||||
|
||||
// Use a local cache if none provided, so we always have conditional flags.
|
||||
SharedScanCache local_cache;
|
||||
if(!cache) {
|
||||
cache = &local_cache;
|
||||
}
|
||||
|
||||
auto getter =
|
||||
std::make_unique<ScanDirectivesGetter>(ScanMode::Fuzzy, cache, instance->getFileManager());
|
||||
instance->setDependencyDirectivesGetter(std::move(getter));
|
||||
|
||||
if(!instance->createTarget()) {
|
||||
return results;
|
||||
}
|
||||
|
||||
auto action = std::make_unique<clang::PreprocessOnlyAction>();
|
||||
|
||||
if(!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
|
||||
return results;
|
||||
}
|
||||
|
||||
instance->getPreprocessor().addPPCallbacks(
|
||||
std::make_unique<FuzzyScanPPCallbacks>(results, *cache, instance->getSourceManager()));
|
||||
|
||||
if(auto error = action->Execute()) {
|
||||
llvm::consumeError(std::move(error));
|
||||
}
|
||||
|
||||
action->EndSourceFile();
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
ScanResult scan_precise(llvm::ArrayRef<const char*> arguments,
|
||||
llvm::StringRef directory,
|
||||
llvm::StringRef content,
|
||||
@@ -558,9 +340,7 @@ ScanResult scan_precise(llvm::ArrayRef<const char*> arguments,
|
||||
return result;
|
||||
}
|
||||
|
||||
auto getter = std::make_unique<ScanDirectivesGetter>(ScanMode::Precise,
|
||||
cache,
|
||||
instance->getFileManager());
|
||||
auto getter = std::make_unique<ScanDirectivesGetter>(cache, instance->getFileManager());
|
||||
instance->setDependencyDirectivesGetter(std::move(getter));
|
||||
|
||||
if(!instance->createTarget()) {
|
||||
|
||||
@@ -33,6 +33,12 @@ struct ScanResult {
|
||||
|
||||
/// Whether the included file was not found during resolution.
|
||||
bool not_found = false;
|
||||
|
||||
/// Whether this is an angled include (<...>) vs quoted ("...").
|
||||
bool is_angled = false;
|
||||
|
||||
/// Whether this is an #include_next directive.
|
||||
bool is_include_next = false;
|
||||
};
|
||||
|
||||
/// Include file names.
|
||||
@@ -55,10 +61,6 @@ struct SharedScanCache {
|
||||
|
||||
/// Scanned directives (referencing tokens above).
|
||||
llvm::SmallVector<clang::dependency_directives_scan::Directive> directives;
|
||||
|
||||
/// Whether each pp_include directive is inside a conditional block,
|
||||
/// computed from the raw directive structure before filtering.
|
||||
std::vector<bool> include_is_conditional;
|
||||
};
|
||||
|
||||
/// path -> cached scan result.
|
||||
@@ -70,17 +72,6 @@ struct SharedScanCache {
|
||||
/// and module_name will be empty.
|
||||
ScanResult scan(llvm::StringRef content);
|
||||
|
||||
/// Fuzzy preprocessing-based scan. Strips #define and conditional directives
|
||||
/// so ALL #include are processed unconditionally. Each include is marked
|
||||
/// with its structural conditional status from the raw directive scan.
|
||||
/// Returns per-file results (main file + all transitively included files).
|
||||
llvm::StringMap<ScanResult>
|
||||
scan_fuzzy(llvm::ArrayRef<const char*> arguments,
|
||||
llvm::StringRef directory,
|
||||
llvm::StringRef content = {},
|
||||
SharedScanCache* cache = nullptr,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr);
|
||||
|
||||
/// Precise preprocessing-based scan. Keeps all directives including #define
|
||||
/// and conditionals. Used for lazy module dependency resolution.
|
||||
ScanResult scan_precise(llvm::ArrayRef<const char*> arguments,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "test/test.h"
|
||||
#include "compile/command.h"
|
||||
#include "command/command.h"
|
||||
#include "compile/compilation.h"
|
||||
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "test/test.h"
|
||||
#include "command/toolchain.h"
|
||||
#include "compile/compilation.h"
|
||||
#include "compile/toolchain.h"
|
||||
#include "support/logging.h"
|
||||
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
@@ -4,21 +4,8 @@
|
||||
namespace clice::testing {
|
||||
namespace {
|
||||
|
||||
/// Helper: find entry in StringMap whose key contains the given substring.
|
||||
template <typename T>
|
||||
auto find_by_substr(llvm::StringMap<T>& map, llvm::StringRef substr) {
|
||||
for(auto it = map.begin(); it != map.end(); ++it) {
|
||||
if(it->first().contains(substr)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return map.end();
|
||||
}
|
||||
|
||||
TEST_SUITE(Scan) {
|
||||
|
||||
// === scan() tests ===
|
||||
|
||||
TEST_CASE(BasicIncludes) {
|
||||
auto result = scan(R"(
|
||||
#include <vector>
|
||||
@@ -143,156 +130,6 @@ int main() {
|
||||
EXPECT_TRUE(result.module_name.empty());
|
||||
}
|
||||
|
||||
// === scan_fuzzy() tests ===
|
||||
|
||||
TEST_CASE(FuzzyBasic) {
|
||||
auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();
|
||||
auto main_path = TestVFS::path("main.cpp");
|
||||
vfs->add("main.cpp", R"(
|
||||
#include "header.h"
|
||||
int main() {}
|
||||
)");
|
||||
vfs->add("header.h", R"(
|
||||
#pragma once
|
||||
int x = 1;
|
||||
)");
|
||||
|
||||
auto args = std::vector<const char*>{"clang++", "-std=c++20", main_path.c_str()};
|
||||
auto results = scan_fuzzy(args, TestVFS::root(), {}, nullptr, vfs);
|
||||
|
||||
auto main_it = find_by_substr(results, "main.cpp");
|
||||
ASSERT_TRUE(main_it != results.end());
|
||||
ASSERT_EQ(main_it->second.includes.size(), 1u);
|
||||
EXPECT_FALSE(main_it->second.includes[0].not_found);
|
||||
EXPECT_FALSE(main_it->second.includes[0].conditional);
|
||||
}
|
||||
|
||||
TEST_CASE(FuzzyConditionalTracking) {
|
||||
auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();
|
||||
auto main_path = TestVFS::path("main.cpp");
|
||||
vfs->add("main.cpp", R"(
|
||||
#include "always.h"
|
||||
#ifdef FOO
|
||||
#include "conditional.h"
|
||||
#endif
|
||||
#include "after.h"
|
||||
)");
|
||||
vfs->add("always.h");
|
||||
vfs->add("conditional.h");
|
||||
vfs->add("after.h");
|
||||
|
||||
auto args = std::vector<const char*>{"clang++", "-std=c++20", main_path.c_str()};
|
||||
auto results = scan_fuzzy(args, TestVFS::root(), {}, nullptr, vfs);
|
||||
|
||||
auto main_it = find_by_substr(results, "main.cpp");
|
||||
ASSERT_TRUE(main_it != results.end());
|
||||
|
||||
auto& includes = main_it->second.includes;
|
||||
ASSERT_EQ(includes.size(), 3u);
|
||||
EXPECT_FALSE(includes[0].conditional); // always.h
|
||||
EXPECT_TRUE(includes[1].conditional); // conditional.h
|
||||
EXPECT_FALSE(includes[2].conditional); // after.h
|
||||
}
|
||||
|
||||
TEST_CASE(FuzzyNotFound) {
|
||||
auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();
|
||||
auto main_path = TestVFS::path("main.cpp");
|
||||
vfs->add("main.cpp", R"(
|
||||
#include "exists.h"
|
||||
#include "missing.h"
|
||||
#include "also_exists.h"
|
||||
)");
|
||||
vfs->add("exists.h");
|
||||
vfs->add("also_exists.h");
|
||||
|
||||
auto args = std::vector<const char*>{"clang++", "-std=c++20", main_path.c_str()};
|
||||
auto results = scan_fuzzy(args, TestVFS::root(), {}, nullptr, vfs);
|
||||
|
||||
auto main_it = find_by_substr(results, "main.cpp");
|
||||
ASSERT_TRUE(main_it != results.end());
|
||||
|
||||
auto& includes = main_it->second.includes;
|
||||
ASSERT_EQ(includes.size(), 3u);
|
||||
EXPECT_FALSE(includes[0].not_found); // exists.h
|
||||
EXPECT_TRUE(includes[1].not_found); // missing.h
|
||||
EXPECT_FALSE(includes[2].not_found); // also_exists.h
|
||||
}
|
||||
|
||||
TEST_CASE(FuzzyTransitiveIncludes) {
|
||||
auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();
|
||||
auto main_path = TestVFS::path("main.cpp");
|
||||
vfs->add("main.cpp", R"(
|
||||
#include "a.h"
|
||||
)");
|
||||
vfs->add("a.h", R"(
|
||||
#pragma once
|
||||
#include "b.h"
|
||||
)");
|
||||
vfs->add("b.h", R"(
|
||||
#pragma once
|
||||
int b = 1;
|
||||
)");
|
||||
|
||||
auto args = std::vector<const char*>{"clang++", "-std=c++20", main_path.c_str()};
|
||||
auto results = scan_fuzzy(args, TestVFS::root(), {}, nullptr, vfs);
|
||||
|
||||
// main.cpp includes a.h
|
||||
auto main_it = find_by_substr(results, "main.cpp");
|
||||
ASSERT_TRUE(main_it != results.end());
|
||||
ASSERT_EQ(main_it->second.includes.size(), 1u);
|
||||
|
||||
// a.h includes b.h
|
||||
auto a_it = find_by_substr(results, "a.h");
|
||||
ASSERT_TRUE(a_it != results.end());
|
||||
ASSERT_EQ(a_it->second.includes.size(), 1u);
|
||||
}
|
||||
|
||||
TEST_CASE(FuzzyWithCache) {
|
||||
auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();
|
||||
auto main_path = TestVFS::path("main.cpp");
|
||||
auto other_path = TestVFS::path("other.cpp");
|
||||
vfs->add("main.cpp", R"(
|
||||
#include "shared.h"
|
||||
)");
|
||||
vfs->add("other.cpp", R"(
|
||||
#include "shared.h"
|
||||
)");
|
||||
vfs->add("shared.h", R"(
|
||||
#pragma once
|
||||
int shared = 1;
|
||||
)");
|
||||
|
||||
SharedScanCache cache;
|
||||
|
||||
auto args1 = std::vector<const char*>{"clang++", "-std=c++20", main_path.c_str()};
|
||||
auto results1 = scan_fuzzy(args1, TestVFS::root(), {}, &cache, vfs);
|
||||
|
||||
// shared.h should be cached after first scan.
|
||||
EXPECT_FALSE(cache.entries.empty());
|
||||
|
||||
auto args2 = std::vector<const char*>{"clang++", "-std=c++20", other_path.c_str()};
|
||||
auto results2 = scan_fuzzy(args2, TestVFS::root(), {}, &cache, vfs);
|
||||
|
||||
// Both scans should find includes.
|
||||
ASSERT_TRUE(find_by_substr(results1, "main.cpp") != results1.end());
|
||||
ASSERT_TRUE(find_by_substr(results2, "other.cpp") != results2.end());
|
||||
}
|
||||
|
||||
TEST_CASE(FuzzyWithContent) {
|
||||
auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();
|
||||
auto main_path = TestVFS::path("main.cpp");
|
||||
vfs->add("main.cpp");
|
||||
vfs->add("header.h");
|
||||
|
||||
auto args = std::vector<const char*>{"clang++", "-std=c++20", main_path.c_str()};
|
||||
auto results = scan_fuzzy(args, TestVFS::root(), R"(#include "header.h")", nullptr, vfs);
|
||||
|
||||
auto main_it = find_by_substr(results, "main.cpp");
|
||||
ASSERT_TRUE(main_it != results.end());
|
||||
ASSERT_EQ(main_it->second.includes.size(), 1u);
|
||||
EXPECT_FALSE(main_it->second.includes[0].not_found);
|
||||
}
|
||||
|
||||
// === scan_precise() tests ===
|
||||
|
||||
TEST_CASE(PreciseBasic) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "test/annotation.h"
|
||||
#include "test/test.h"
|
||||
#include "compile/command.h"
|
||||
#include "command/command.h"
|
||||
#include "compile/compilation.h"
|
||||
#include "eventide/ipc/lsp/protocol.h"
|
||||
#include "support/logging.h"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "eventide/deco/macro.h"
|
||||
#include "eventide/deco/runtime.h"
|
||||
#include "eventide/deco/deco.h"
|
||||
#include "eventide/zest/zest.h"
|
||||
#include "support/filesystem.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user