Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/Compiler/Compilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions include/Compiler/CompilationUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ class CompilationUnit {
/// 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,
Expand Down
3 changes: 3 additions & 0 deletions include/Test/Tester.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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) {
Expand Down
96 changes: 46 additions & 50 deletions src/Compiler/Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@ class ProxyASTConsumer final : public clang::MultiplexConsumer {
public:
ProxyASTConsumer(std::unique_ptr<clang::ASTConsumer> consumer,
clang::CompilerInstance& instance,
std::vector<clang::Decl*>& top_level_decls,
std::vector<clang::Decl*>* top_level_decls,
std::shared_ptr<std::atomic_bool> 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();
Expand All @@ -32,12 +29,12 @@ class ProxyASTConsumer final : public clang::MultiplexConsumer {
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);
Expand All @@ -57,24 +54,25 @@ class ProxyASTConsumer final : public clang::MultiplexConsumer {
}

private:
bool need_collect;
clang::CompilerInstance& instance;
clang::SourceManager& src_mgr;
std::vector<clang::Decl*>& top_level_decls;

/// Non-nullptr if we need collect the top level declarations.
std::vector<clang::Decl*>* top_level_decls;

std::shared_ptr<std::atomic_bool> stop;
};

class ProxyAction final : public clang::WrapperFrontendAction {
public:
ProxyAction(std::unique_ptr<clang::FrontendAction> action,
std::vector<clang::Decl*>* top_level_decls,
std::shared_ptr<std::atomic_bool> 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<clang::ASTConsumer> final {

bool need_collect = instance.getFrontendOpts().OutputFile.empty();

return std::make_unique<ProxyASTConsumer>(
WrapperFrontendAction::CreateASTConsumer(instance, file),
instance,
Expand All @@ -85,12 +83,8 @@ class ProxyAction final : public clang::WrapperFrontendAction {
/// Make this public.
using clang::WrapperFrontendAction::EndSourceFile;

auto pop_decls() {
return std::move(top_level_decls);
}

private:
std::vector<clang::Decl*> top_level_decls;
std::vector<clang::Decl*>* top_level_decls;
std::shared_ptr<std::atomic_bool> stop;
};

Expand Down Expand Up @@ -148,10 +142,16 @@ auto create_invocation(CompilationParams& params,
return invocation;
}

template <typename Action>
/// Do nothing before or after compile state.
constexpr static auto no_hook = [](auto& /*ignore*/) {
};

template <typename Action,
typename BeforeExecute = decltype(no_hook),
typename AfterExecute = decltype(no_hook)>
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<std::vector<Diagnostic>>();
auto diagnostic_engine =
Expand Down Expand Up @@ -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<ProxyAction>(std::make_unique<Action>(), params.stop);
/// Frontend information ...
std::vector<clang::Decl*> top_level_decls;
llvm::DenseMap<clang::FileID, Directive> directives;
std::optional<clang::syntax::TokenCollector> token_collector;

auto action = std::make_unique<ProxyAction>(
std::make_unique<Action>(),
/// 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");
Expand All @@ -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<clang::FileID, Directive> directives;
Directive::attach(pp, directives);

/// Collect tokens.
std::optional<clang::syntax::TokenCollector> 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()) {
Expand All @@ -227,9 +230,9 @@ CompilationResult run_clang(CompilationParams& params,
return std::unexpected("Compilation is canceled.");
}

std::optional<clang::syntax::TokenBuffer> tok_buf;
if(tok_collector) {
tok_buf = std::move(*tok_collector).consume();
std::optional<clang::syntax::TokenBuffer> token_buffer;
if(token_collector) {
token_buffer = std::move(*token_collector).consume();
}

/// FIXME: getDependencies currently return ArrayRef<std::string>, which actually results in
Expand All @@ -240,35 +243,33 @@ 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<clang::FileID, llvm::StringRef>(),
.symbolHashCache = llvm::DenseMap<const void*, std::uint64_t>(),
.diagnostics = diagnostics,
.top_level_decls = std::move(top_level_decls),
};

CompilationUnit unit(CompilationUnit::SyntaxOnly, impl);
CompilationUnit unit(CompilationUnit::Content, impl);
Comment thread
16bit-ykiko marked this conversation as resolved.
Outdated
after_execute(unit);
return unit;
}

} // namespace

CompilationResult preprocess(CompilationParams& params) {
return run_clang<clang::PreprocessOnlyAction>(params, [](auto&) {}, [](auto&) {});
return run_clang<clang::PreprocessOnlyAction>(params);
}

CompilationResult compile(CompilationParams& params) {
return run_clang<clang::SyntaxOnlyAction>(params, [](auto&) {}, [](auto&) {});
return run_clang<clang::SyntaxOnlyAction>(params);
Comment thread
16bit-ykiko marked this conversation as resolved.
}

CompilationResult compile(CompilationParams& params, PCHInfo& out) {
Expand Down Expand Up @@ -342,18 +343,13 @@ CompilationResult complete(CompilationParams& params, clang::CodeCompleteConsume
column += 1;
}

return run_clang<clang::SyntaxOnlyAction>(
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<clang::SyntaxOnlyAction>(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
2 changes: 2 additions & 0 deletions src/Server/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ async::Task<bool> 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;
Expand Down Expand Up @@ -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()};
Expand Down
2 changes: 2 additions & 0 deletions src/Server/Feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()};
Expand Down Expand Up @@ -75,6 +76,7 @@ async::Task<json::Value> 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()};
Expand Down
1 change: 1 addition & 0 deletions src/Server/Indexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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); });
Expand Down
3 changes: 1 addition & 2 deletions tests/unit/Compiler/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

Expand Down