From cbb210c027fb34d3185c5bcc55d3bc9ee8455b8a Mon Sep 17 00:00:00 2001 From: Shiyu Date: Sun, 24 Aug 2025 00:57:53 +0800 Subject: [PATCH] Chore: explicitly set compilation kind (#184) Co-authored-by: ykiko --- include/Compiler/Compilation.h | 3 + include/Compiler/CompilationUnit.h | 4 +- include/Test/Tester.h | 3 + src/Compiler/Compilation.cpp | 96 ++++++++++++++---------------- src/Server/Document.cpp | 2 + src/Server/Feature.cpp | 2 + src/Server/Indexer.cpp | 1 + tests/unit/Compiler/Compiler.cpp | 3 +- 8 files changed, 60 insertions(+), 54 deletions(-) diff --git a/include/Compiler/Compilation.h b/include/Compiler/Compilation.h index e115a523..ed95d99f 100644 --- a/include/Compiler/Compilation.h +++ b/include/Compiler/Compilation.h @@ -12,6 +12,9 @@ class CodeCompleteConsumer; namespace clice { struct CompilationParams { + /// The kind of this compilation. + CompilationUnit::Kind kind; + /// Output file path. llvm::SmallString<128> output_file; diff --git a/include/Compiler/CompilationUnit.h b/include/Compiler/CompilationUnit.h index 029e6625..a79bc674 100644 --- a/include/Compiler/CompilationUnit.h +++ b/include/Compiler/CompilationUnit.h @@ -28,9 +28,9 @@ public: /// From building precompiled module for the module interface unit. ModuleInterface, - /// From building normal AST for source file, interested file and top level + /// From building normal AST for source file(except preamble), interested file and top level /// declarations are available. - SyntaxOnly, + Content, /// From running code completion for the source file(preamble is applied). Completion, diff --git a/include/Test/Tester.h b/include/Test/Tester.h index 3d3b0b97..2abfc8df 100644 --- a/include/Test/Tester.h +++ b/include/Test/Tester.h @@ -35,6 +35,7 @@ struct Tester { auto command = std::format("clang++ {} {} -fms-extensions", standard, src_path); database.update_command("fake", src_path, command); + params.kind = CompilationUnit::Content; params.arguments = database.get_command(src_path, true, true).arguments; for(auto& [file, source]: sources.all_files) { @@ -65,6 +66,7 @@ struct Tester { auto command = std::format("clang++ {} {} -fms-extensions", standard, src_path); database.update_command("fake", src_path, command); + params.kind = CompilationUnit::Preamble; params.arguments = database.get_command(src_path, true, true).arguments; auto path = fs::createTemporaryFile("clice", "pch"); @@ -100,6 +102,7 @@ struct Tester { /// Build AST params.output_file.clear(); + params.kind = CompilationUnit::Content; params.pch = {info.path, info.preamble.size()}; for(auto& [file, source]: sources.all_files) { if(file == src_path) { diff --git a/src/Compiler/Compilation.cpp b/src/Compiler/Compilation.cpp index 89ef2ec7..bf6da8fd 100644 --- a/src/Compiler/Compilation.cpp +++ b/src/Compiler/Compilation.cpp @@ -15,13 +15,10 @@ class ProxyASTConsumer final : public clang::MultiplexConsumer { public: ProxyASTConsumer(std::unique_ptr consumer, clang::CompilerInstance& instance, - std::vector& top_level_decls, + std::vector* top_level_decls, std::shared_ptr stop) : clang::MultiplexConsumer(std::move(consumer)), instance(instance), - src_mgr(instance.getSourceManager()), top_level_decls(top_level_decls), stop(stop) { - /// FIXME: We may want to use a more explicit way to judge this. - need_collect = instance.getFrontendOpts().OutputFile.empty(); - } + src_mgr(instance.getSourceManager()), top_level_decls(top_level_decls), stop(stop) {} void collect_decl(clang::Decl* decl) { auto location = decl->getLocation(); @@ -32,12 +29,12 @@ public: location = src_mgr.getExpansionLoc(location); auto fid = src_mgr.getFileID(location); if(fid == src_mgr.getPreambleFileID() || fid == src_mgr.getMainFileID()) { - top_level_decls.push_back(decl); + top_level_decls->push_back(decl); } } auto HandleTopLevelDecl(clang::DeclGroupRef group) -> bool final { - if(need_collect) { + if(top_level_decls) { if(group.isDeclGroup()) { for(auto decl: group) { collect_decl(decl); @@ -57,24 +54,25 @@ public: } private: - bool need_collect; clang::CompilerInstance& instance; clang::SourceManager& src_mgr; - std::vector& top_level_decls; + + /// Non-nullptr if we need collect the top level declarations. + std::vector* top_level_decls; + std::shared_ptr stop; }; class ProxyAction final : public clang::WrapperFrontendAction { public: ProxyAction(std::unique_ptr action, + std::vector* top_level_decls, std::shared_ptr stop) : - clang::WrapperFrontendAction(std::move(action)), stop(std::move(stop)) {} + clang::WrapperFrontendAction(std::move(action)), top_level_decls(top_level_decls), + stop(std::move(stop)) {} auto CreateASTConsumer(clang::CompilerInstance& instance, llvm::StringRef file) -> std::unique_ptr final { - - bool need_collect = instance.getFrontendOpts().OutputFile.empty(); - return std::make_unique( WrapperFrontendAction::CreateASTConsumer(instance, file), instance, @@ -85,12 +83,8 @@ public: /// Make this public. using clang::WrapperFrontendAction::EndSourceFile; - auto pop_decls() { - return std::move(top_level_decls); - } - private: - std::vector top_level_decls; + std::vector* top_level_decls; std::shared_ptr stop; }; @@ -148,10 +142,16 @@ auto create_invocation(CompilationParams& params, return invocation; } -template +/// Do nothing before or after compile state. +constexpr static auto no_hook = [](auto& /*ignore*/) { +}; + +template CompilationResult run_clang(CompilationParams& params, - const auto& before_execute, - const auto& after_execute) { + const BeforeExecute& before_execute = no_hook, + const AfterExecute& after_execute = no_hook) { auto diagnostics = params.diagnostics ? params.diagnostics : std::make_shared>(); auto diagnostic_engine = @@ -181,7 +181,16 @@ CompilationResult run_clang(CompilationParams& params, /// Adjust the compiler instance, for example, set preamble or modules. before_execute(*instance); - auto action = std::make_unique(std::make_unique(), params.stop); + /// Frontend information ... + std::vector top_level_decls; + llvm::DenseMap directives; + std::optional token_collector; + + auto action = std::make_unique( + std::make_unique(), + /// We only collect top level declarations for parse main file. + params.kind == CompilationUnit::Content ? &top_level_decls : nullptr, + params.stop); if(!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) { return std::unexpected("Fail to begin source file"); @@ -192,18 +201,12 @@ CompilationResult run_clang(CompilationParams& params, /// `BeginSourceFile` may create new preprocessor, so all operations related to preprocessor /// should be done after `BeginSourceFile`. - - /// Collect directives. - llvm::DenseMap directives; Directive::attach(pp, directives); - /// Collect tokens. - std::optional tok_collector; - /// It is not necessary to collect tokens if we are running code completion. /// And in fact will cause assertion failure. if(!instance->hasCodeCompletionConsumer()) { - tok_collector.emplace(pp); + token_collector.emplace(pp); } if(auto error = action->Execute()) { @@ -227,9 +230,9 @@ CompilationResult run_clang(CompilationParams& params, return std::unexpected("Compilation is canceled."); } - std::optional tok_buf; - if(tok_collector) { - tok_buf = std::move(*tok_collector).consume(); + std::optional token_buffer; + if(token_collector) { + token_buffer = std::move(*token_collector).consume(); } /// FIXME: getDependencies currently return ArrayRef, which actually results in @@ -240,15 +243,13 @@ CompilationResult run_clang(CompilationParams& params, resolver.emplace(instance->getSema()); } - auto top_level_decls = action->pop_decls(); - auto impl = new CompilationUnit::Impl{ .interested = pp.getSourceManager().getMainFileID(), .src_mgr = instance->getSourceManager(), .action = std::move(action), .instance = std::move(instance), .m_resolver = std::move(resolver), - .buffer = std::move(tok_buf), + .buffer = std::move(token_buffer), .m_directives = std::move(directives), .pathCache = llvm::DenseMap(), .symbolHashCache = llvm::DenseMap(), @@ -256,7 +257,7 @@ CompilationResult run_clang(CompilationParams& params, .top_level_decls = std::move(top_level_decls), }; - CompilationUnit unit(CompilationUnit::SyntaxOnly, impl); + CompilationUnit unit(params.kind, impl); after_execute(unit); return unit; } @@ -264,11 +265,11 @@ CompilationResult run_clang(CompilationParams& params, } // namespace CompilationResult preprocess(CompilationParams& params) { - return run_clang(params, [](auto&) {}, [](auto&) {}); + return run_clang(params); } CompilationResult compile(CompilationParams& params) { - return run_clang(params, [](auto&) {}, [](auto&) {}); + return run_clang(params); } CompilationResult compile(CompilationParams& params, PCHInfo& out) { @@ -342,18 +343,13 @@ CompilationResult complete(CompilationParams& params, clang::CodeCompleteConsume column += 1; } - return run_clang( - params, - [&](clang::CompilerInstance& instance) { - /// Set options to run code completion. - instance.getFrontendOpts().CodeCompletionAt.FileName = std::move(file); - instance.getFrontendOpts().CodeCompletionAt.Line = line; - instance.getFrontendOpts().CodeCompletionAt.Column = column; - instance.setCodeCompletionConsumer(consumer); - }, - [&](CompilationUnit& unit) { - /// - }); + return run_clang(params, [&](clang::CompilerInstance& instance) { + /// Set options to run code completion. + instance.getFrontendOpts().CodeCompletionAt.FileName = std::move(file); + instance.getFrontendOpts().CodeCompletionAt.Line = line; + instance.getFrontendOpts().CodeCompletionAt.Column = column; + instance.setCodeCompletionConsumer(consumer); + }); } } // namespace clice diff --git a/src/Server/Document.cpp b/src/Server/Document.cpp index b4d56221..1436cfeb 100644 --- a/src/Server/Document.cpp +++ b/src/Server/Document.cpp @@ -183,6 +183,7 @@ async::Task build_pch_task(CompilationDatabase::LookupInfo& info, diagnostics->clear(); CompilationParams params; + params.kind = CompilationUnit::Preamble; params.output_file = path::join(config::cache.dir, path::filename(path) + ".pch"); params.arguments = std::move(info.arguments); params.diagnostics = diagnostics; @@ -294,6 +295,7 @@ async::Task<> Server::build_ast(std::string path, std::string content) { } CompilationParams params; + params.kind = CompilationUnit::Content; params.arguments = database.get_command(path, true, true).arguments; params.add_remapped_file(path, content); params.pch = {pch->path, pch->preamble.size()}; diff --git a/src/Server/Feature.cpp b/src/Server/Feature.cpp index 50911f8f..3f880eb1 100644 --- a/src/Server/Feature.cpp +++ b/src/Server/Feature.cpp @@ -27,6 +27,7 @@ auto Server::on_completion(proto::CompletionParams params) -> Result { { /// Set compilation params ... . CompilationParams params; + params.kind = CompilationUnit::Completion; params.arguments = database.get_command(path, true).arguments; params.add_remapped_file(path, content); params.pch = {pch->path, pch->preamble.size()}; @@ -75,6 +76,7 @@ async::Task Server::on_signature_help(proto::SignatureHelpParams pa { /// Set compilation params ... . CompilationParams params; + params.kind = CompilationUnit::Completion; params.arguments = database.get_command(path, true).arguments; params.add_remapped_file(path, content); params.pch = {pch->path, pch->preamble.size()}; diff --git a/src/Server/Indexer.cpp b/src/Server/Indexer.cpp index 699df77f..57c76dca 100644 --- a/src/Server/Indexer.cpp +++ b/src/Server/Indexer.cpp @@ -47,6 +47,7 @@ async::Task<> Indexer::index(CompilationUnit& unit) { async::Task<> Indexer::index(llvm::StringRef file) { CompilationParams params; + params.kind = CompilationUnit::Indexing; params.arguments = database.get_command(file).arguments; auto AST = co_await async::submit([&] { return compile(params); }); diff --git a/tests/unit/Compiler/Compiler.cpp b/tests/unit/Compiler/Compiler.cpp index 6af2a8e5..3ae274d2 100644 --- a/tests/unit/Compiler/Compiler.cpp +++ b/tests/unit/Compiler/Compiler.cpp @@ -30,8 +30,7 @@ struct Bar { )"; tester.add_main("main.cpp", content); - tester.compile_with_pch(); - + expect(that % tester.compile_with_pch() == true); expect(that % tester.unit->top_level_decls().size() == 4); };