Improve compiling (#140)
This commit is contained in:
@@ -16,13 +16,13 @@ bool RAVFileter::filterable(clang::SourceRange range) const {
|
||||
auto [fid, offset] = unit.decompose_location(unit.expansion_location(begin));
|
||||
|
||||
/// For builtin files, we don't want to visit them.
|
||||
if(unit.isBuiltinFile(fid)) {
|
||||
if(unit.is_builtin_file(fid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Filter out if the location is not in the interested file.
|
||||
if(interestedOnly) {
|
||||
auto interested = unit.getInterestedFile();
|
||||
auto interested = unit.interested_file();
|
||||
if(fid != interested) {
|
||||
return true;
|
||||
}
|
||||
@@ -35,12 +35,12 @@ bool RAVFileter::filterable(clang::SourceRange range) const {
|
||||
auto [beginFID, beginOffset] = unit.decompose_location(unit.expansion_location(begin));
|
||||
auto [endFID, endOffset] = unit.decompose_location(unit.expansion_location(end));
|
||||
|
||||
if(unit.isBuiltinFile(beginFID) || unit.isBuiltinFile(endFID)) {
|
||||
if(unit.is_builtin_file(beginFID) || unit.is_builtin_file(endFID)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(interestedOnly) {
|
||||
auto interested = unit.getInterestedFile();
|
||||
auto interested = unit.interested_file();
|
||||
if(beginFID != interested && endFID != interested) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace clice {
|
||||
|
||||
std::expected<void, std::string> mangleCommand(llvm::StringRef command,
|
||||
std::expected<void, std::string> mangle_command(llvm::StringRef command,
|
||||
llvm::SmallVectorImpl<const char*>& out,
|
||||
llvm::SmallVectorImpl<char>& buffer) {
|
||||
llvm::SmallString<128> current;
|
||||
|
||||
@@ -1,32 +1,84 @@
|
||||
#include "CompilationUnitImpl.h"
|
||||
#include "Compiler/Command.h"
|
||||
#include "Compiler/Compilation.h"
|
||||
|
||||
#include "Compiler/Diagnostic.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
|
||||
#define TRY_OR_RETURN(expr) \
|
||||
do { \
|
||||
auto&& macro_result = (expr); \
|
||||
if(!macro_result.has_value()) { \
|
||||
return std::unexpected(std::move(macro_result.error())); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ASSIGN_OR_RETURN(var, expr) \
|
||||
do { \
|
||||
auto&& macro_result = (expr); \
|
||||
if(!macro_result.has_value()) { \
|
||||
return std::unexpected(std::move(macro_result.error())); \
|
||||
} \
|
||||
var = std::move(*macro_result); \
|
||||
} while(0)
|
||||
|
||||
namespace clice {
|
||||
|
||||
namespace {
|
||||
|
||||
std::unique_ptr<clang::CompilerInvocation> createInvocation(CompilationParams& params) {
|
||||
llvm::SmallString<1024> buffer;
|
||||
llvm::SmallVector<const char*, 16> args;
|
||||
|
||||
if(auto result = mangleCommand(params.command, args, buffer); !result) {
|
||||
std::abort();
|
||||
std::unexpected<std::string> report_diagnostics(llvm::StringRef message,
|
||||
std::vector<Diagnostic>& diagnostics) {
|
||||
std::string error = message.str();
|
||||
for(auto& diagnostic: diagnostics) {
|
||||
error += std::format("{}\n", diagnostic.message);
|
||||
}
|
||||
return std::unexpected(std::move(error));
|
||||
}
|
||||
|
||||
clang::CreateInvocationOptions options = {};
|
||||
options.VFS = params.vfs;
|
||||
/// create a `clang::CompilerInvocation` for compilation, it set and reset
|
||||
/// all necessary arguments and flags for clice compilation.
|
||||
auto create_invocation(CompilationParams& params,
|
||||
std::shared_ptr<std::vector<Diagnostic>>& diagnostics,
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine>& diagnostic_engine)
|
||||
-> std::expected<std::unique_ptr<clang::CompilerInvocation>, std::string> {
|
||||
|
||||
/// Split orgin command into c-style command arguments for creating invocation.
|
||||
llvm::SmallString<1024> buffer;
|
||||
llvm::SmallVector<const char*, 32> args;
|
||||
TRY_OR_RETURN(mangle_command(params.command, args, buffer));
|
||||
|
||||
/// Create clang invocation.
|
||||
clang::CreateInvocationOptions options = {
|
||||
.Diags = diagnostic_engine,
|
||||
.VFS = params.vfs,
|
||||
};
|
||||
|
||||
auto invocation = clang::createInvocation(args, options);
|
||||
if(!invocation) {
|
||||
std::abort();
|
||||
return report_diagnostics("fail to create compiler invocation", *diagnostics);
|
||||
}
|
||||
|
||||
auto& frontOpts = invocation->getFrontendOpts();
|
||||
frontOpts.DisableFree = false;
|
||||
auto& pp_opts = invocation->getPreprocessorOpts();
|
||||
assert(!pp_opts.RetainRemappedFileBuffers && "RetainRemappedFileBuffers should be false");
|
||||
|
||||
for(auto& [file, buffer]: params.buffers) {
|
||||
pp_opts.addRemappedFile(file, buffer.release());
|
||||
}
|
||||
params.buffers.clear();
|
||||
|
||||
auto [pch, bound] = params.pch;
|
||||
pp_opts.ImplicitPCHInclude = std::move(pch);
|
||||
if(bound != 0) {
|
||||
pp_opts.PrecompiledPreambleBytes = {bound, false};
|
||||
}
|
||||
|
||||
auto& header_search_opts = invocation->getHeaderSearchOpts();
|
||||
for(auto& [name, path]: params.pcms) {
|
||||
header_search_opts.PrebuiltModuleFiles.try_emplace(name.str(), std::move(path));
|
||||
}
|
||||
|
||||
auto& front_opts = invocation->getFrontendOpts();
|
||||
front_opts.DisableFree = false;
|
||||
|
||||
clang::LangOptions& langOpts = invocation->getLangOpts();
|
||||
langOpts.CommentOpts.ParseAllComments = true;
|
||||
@@ -35,50 +87,21 @@ std::unique_ptr<clang::CompilerInvocation> createInvocation(CompilationParams& p
|
||||
return invocation;
|
||||
}
|
||||
|
||||
class CliceASTConsumer : public clang::ASTConsumer {
|
||||
public:
|
||||
CliceASTConsumer(std::vector<clang::Decl*>& top_level_decls,
|
||||
const std::shared_ptr<std::atomic<bool>>& contiune_parse) :
|
||||
top_level_decls(top_level_decls), contiune_parse(contiune_parse) {}
|
||||
template <typename Action, typename Adjuster>
|
||||
std::expected<CompilationUnit, std::string> clang_compile(CompilationParams& params,
|
||||
const Adjuster& adjuster) {
|
||||
auto diagnostics = std::make_shared<std::vector<Diagnostic>>();
|
||||
auto diagnostic_engine =
|
||||
clang::CompilerInstance::createDiagnostics(*params.vfs,
|
||||
new clang::DiagnosticOptions(),
|
||||
Diagnostic::create(diagnostics));
|
||||
|
||||
bool HandleTopLevelDecl(clang::DeclGroupRef group) override {
|
||||
for(auto decl: group) {
|
||||
top_level_decls.emplace_back(decl);
|
||||
}
|
||||
return *contiune_parse;
|
||||
}
|
||||
auto invocation = create_invocation(params, diagnostics, diagnostic_engine);
|
||||
TRY_OR_RETURN(invocation);
|
||||
|
||||
private:
|
||||
std::vector<clang::Decl*>& top_level_decls;
|
||||
std::shared_ptr<std::atomic<bool>> contiune_parse;
|
||||
};
|
||||
|
||||
class ProxyASTConsumer {};
|
||||
|
||||
class CliceFrontendAction : public clang::SyntaxOnlyAction {
|
||||
public:
|
||||
CliceFrontendAction(std::unique_ptr<clang::ASTConsumer>& consumer) :
|
||||
consumer(std::move(consumer)) {}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& instance,
|
||||
llvm::StringRef file) override {
|
||||
return std::move(consumer);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<clang::ASTConsumer> consumer;
|
||||
};
|
||||
|
||||
std::unique_ptr<clang::CompilerInstance> createInstance(CompilationParams& params) {
|
||||
auto instance = std::make_unique<clang::CompilerInstance>();
|
||||
|
||||
instance->setInvocation(createInvocation(params));
|
||||
|
||||
/// TODO: use a thread safe filesystem and our customized `DiagnosticConsumer`.
|
||||
instance->createDiagnostics(
|
||||
*params.vfs,
|
||||
new clang::TextDiagnosticPrinter(llvm::outs(), new clang::DiagnosticOptions()),
|
||||
true);
|
||||
instance->setInvocation(std::move(*invocation));
|
||||
instance->setDiagnostics(diagnostic_engine.get());
|
||||
|
||||
if(auto remapping = clang::createVFSFromCompilerInvocation(instance->getInvocation(),
|
||||
instance->getDiagnostics(),
|
||||
@@ -86,70 +109,18 @@ std::unique_ptr<clang::CompilerInstance> createInstance(CompilationParams& param
|
||||
instance->createFileManager(std::move(remapping));
|
||||
}
|
||||
|
||||
/// Add remapped files, if bounds is provided, cut off the content.
|
||||
std::size_t size = params.bound.has_value() ? params.bound.value() : params.content.size();
|
||||
|
||||
assert(!instance->getPreprocessorOpts().RetainRemappedFileBuffers &&
|
||||
"RetainRemappedFileBuffers should be false");
|
||||
|
||||
if(!params.content.empty()) {
|
||||
instance->getPreprocessorOpts().addRemappedFile(
|
||||
params.srcPath,
|
||||
llvm::MemoryBuffer::getMemBufferCopy(params.content.substr(0, size), params.srcPath)
|
||||
.release());
|
||||
}
|
||||
|
||||
/// Add all remapped file.
|
||||
for(auto& [file, buffer]: params.buffers) {
|
||||
instance->getPreprocessorOpts().addRemappedFile(file, buffer.release());
|
||||
}
|
||||
params.buffers.clear();
|
||||
|
||||
if(!instance->createTarget()) {
|
||||
std::abort();
|
||||
return std::unexpected("fail to create target");
|
||||
}
|
||||
|
||||
auto [pch, bound] = params.pch;
|
||||
/// Adjust the compiler instance, for example, set preamble or modules.
|
||||
adjuster(*instance);
|
||||
|
||||
auto& PPOpts = instance->getPreprocessorOpts();
|
||||
PPOpts.ImplicitPCHInclude = std::move(pch);
|
||||
|
||||
if(bound != 0) {
|
||||
PPOpts.PrecompiledPreambleBytes = {bound, false};
|
||||
}
|
||||
|
||||
for(auto& [name, path]: params.pcms) {
|
||||
auto& HSOpts = instance->getHeaderSearchOpts();
|
||||
HSOpts.PrebuiltModuleFiles.try_emplace(name.str(), std::move(path));
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Execute given action with the on the given instance. `callback` is called after
|
||||
/// `BeginSourceFile`. Beacuse `BeginSourceFile` may create new preprocessor.
|
||||
std::expected<void, std::string> ExecuteAction(clang::CompilerInstance& instance,
|
||||
clang::FrontendAction& action,
|
||||
auto&& callback) {
|
||||
if(!action.BeginSourceFile(instance, instance.getFrontendOpts().Inputs[0])) {
|
||||
return std::unexpected("Failed to begin source file");
|
||||
}
|
||||
|
||||
callback();
|
||||
|
||||
if(auto error = action.Execute()) {
|
||||
return std::unexpected(std::format("Failed to execute action, because {} ", error));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::expected<CompilationUnit, std::string>
|
||||
ExecuteAction(std::unique_ptr<clang::CompilerInstance> instance,
|
||||
std::unique_ptr<clang::FrontendAction> action) {
|
||||
auto action = std::make_unique<Action>();
|
||||
|
||||
if(!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
|
||||
return std::unexpected("Failed to begin source file");
|
||||
/// TODO: collect error message from diagnostics.
|
||||
return report_diagnostics("Failed to begin source file", *diagnostics);
|
||||
}
|
||||
|
||||
auto& pp = instance->getPreprocessor();
|
||||
@@ -198,26 +169,24 @@ std::expected<CompilationUnit, std::string>
|
||||
.m_directives = std::move(directives),
|
||||
.pathCache = llvm::DenseMap<clang::FileID, llvm::StringRef>(),
|
||||
.symbolHashCache = llvm::DenseMap<const void*, std::uint64_t>(),
|
||||
.diagnostics = diagnostics,
|
||||
};
|
||||
|
||||
|
||||
return CompilationUnit(CompilationUnit::SyntaxOnly, impl);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::expected<CompilationUnit, std::string> preprocess(CompilationParams& params) {
|
||||
auto instance = createInstance(params);
|
||||
return ExecuteAction(std::move(instance), std::make_unique<clang::PreprocessOnlyAction>());
|
||||
return clang_compile<clang::PreprocessOnlyAction>(params, [](auto&) {});
|
||||
}
|
||||
|
||||
std::expected<CompilationUnit, std::string> compile(CompilationParams& params) {
|
||||
auto instance = createInstance(params);
|
||||
return ExecuteAction(std::move(instance), std::make_unique<clang::SyntaxOnlyAction>());
|
||||
return clang_compile<clang::SyntaxOnlyAction>(params, [](auto&) {});
|
||||
}
|
||||
|
||||
std::expected<CompilationUnit, std::string> compile(CompilationParams& params,
|
||||
clang::CodeCompleteConsumer* consumer) {
|
||||
auto instance = createInstance(params);
|
||||
std::expected<CompilationUnit, std::string> complete(CompilationParams& params,
|
||||
clang::CodeCompleteConsumer* consumer) {
|
||||
|
||||
auto& [file, offset] = params.completion;
|
||||
|
||||
@@ -225,14 +194,9 @@ std::expected<CompilationUnit, std::string> compile(CompilationParams& params,
|
||||
std::uint32_t line = 1;
|
||||
std::uint32_t column = 1;
|
||||
|
||||
llvm::StringRef content;
|
||||
if(file == params.srcPath) {
|
||||
content = params.content;
|
||||
} else {
|
||||
auto it = params.buffers.find(file);
|
||||
assert(it != params.buffers.end() && "completion must occur in remapped file.");
|
||||
content = it->second->getBuffer();
|
||||
}
|
||||
/// FIXME:
|
||||
assert(params.buffers.size() == 1);
|
||||
llvm::StringRef content = params.buffers.begin()->second->getBuffer();
|
||||
|
||||
for(auto c: content.substr(0, offset)) {
|
||||
if(c == '\n') {
|
||||
@@ -243,62 +207,47 @@ std::expected<CompilationUnit, std::string> compile(CompilationParams& params,
|
||||
column += 1;
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
||||
return ExecuteAction(std::move(instance), std::make_unique<clang::SyntaxOnlyAction>());
|
||||
return clang_compile<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);
|
||||
});
|
||||
}
|
||||
|
||||
std::expected<CompilationUnit, std::string> compile(CompilationParams& params, PCHInfo& out) {
|
||||
assert(params.bound.has_value() && "Preamble bounds is required to build PCH");
|
||||
/// assert(params.bound.has_value() && "Preamble bounds is required to build PCH");
|
||||
|
||||
auto instance = createInstance(params);
|
||||
out.path = params.outPath.str();
|
||||
/// out.preamble = params.content.substr(0, *params.bound);
|
||||
out.command = params.command.str();
|
||||
/// FIXME: out.deps = info->deps();
|
||||
|
||||
llvm::StringRef outPath = params.outPath.str();
|
||||
|
||||
/// Set options to generate PCH.
|
||||
instance->getFrontendOpts().OutputFile = outPath;
|
||||
instance->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH;
|
||||
instance->getPreprocessorOpts().GeneratePreamble = true;
|
||||
instance->getLangOpts().CompilingPCH = true;
|
||||
|
||||
if(auto info =
|
||||
ExecuteAction(std::move(instance), std::make_unique<clang::GeneratePCHAction>())) {
|
||||
out.path = outPath;
|
||||
out.preamble = params.content.substr(0, *params.bound);
|
||||
out.command = params.command.str();
|
||||
out.deps = info->deps();
|
||||
return std::move(*info);
|
||||
} else {
|
||||
return std::unexpected(info.error());
|
||||
}
|
||||
return clang_compile<clang::GeneratePCHAction>(params, [&](clang::CompilerInstance& instance) {
|
||||
/// Set options to generate PCH.
|
||||
instance.getFrontendOpts().OutputFile = params.outPath.str();
|
||||
instance.getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH;
|
||||
instance.getPreprocessorOpts().GeneratePreamble = true;
|
||||
instance.getLangOpts().CompilingPCH = true;
|
||||
});
|
||||
}
|
||||
|
||||
std::expected<CompilationUnit, std::string> compile(CompilationParams& params, PCMInfo& out) {
|
||||
auto instance = createInstance(params);
|
||||
|
||||
/// Set options to generate PCM.
|
||||
instance->getFrontendOpts().OutputFile = params.outPath.str();
|
||||
instance->getFrontendOpts().ProgramAction = clang::frontend::GenerateReducedModuleInterface;
|
||||
|
||||
if(auto info = ExecuteAction(std::move(instance),
|
||||
std::make_unique<clang::GenerateReducedModuleInterfaceAction>())) {
|
||||
assert(info->is_module_interface_unit() &&
|
||||
"Only module interface unit could be built as PCM");
|
||||
out.isInterfaceUnit = true;
|
||||
out.name = info->module_name();
|
||||
for(auto& [name, path]: params.pcms) {
|
||||
out.mods.emplace_back(name);
|
||||
}
|
||||
out.path = params.outPath.str();
|
||||
out.srcPath = params.srcPath.str();
|
||||
return std::move(*info);
|
||||
} else {
|
||||
return std::unexpected(info.error());
|
||||
for(auto& [name, path]: params.pcms) {
|
||||
out.mods.emplace_back(name);
|
||||
}
|
||||
out.path = params.outPath.str();
|
||||
|
||||
return clang_compile<clang::GenerateReducedModuleInterfaceAction>(
|
||||
params,
|
||||
[&](clang::CompilerInstance& instance) {
|
||||
/// Set options to generate PCH.
|
||||
instance.getFrontendOpts().OutputFile = params.outPath.str();
|
||||
instance.getFrontendOpts().ProgramAction =
|
||||
clang::frontend::GenerateReducedModuleInterface;
|
||||
out.srcPath = instance.getFrontendOpts().Inputs[0].getFile();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -229,15 +229,15 @@ index::SymbolID CompilationUnit::getSymbolID(const clang::MacroInfo* macro) {
|
||||
return index::SymbolID{hash, name.str()};
|
||||
}
|
||||
|
||||
clang::FileID CompilationUnit::getInterestedFile() {
|
||||
clang::FileID CompilationUnit::interested_file() {
|
||||
return impl->interested;
|
||||
}
|
||||
|
||||
llvm::StringRef CompilationUnit::getInterestedFileContent() {
|
||||
llvm::StringRef CompilationUnit::interested_content() {
|
||||
return file_content(impl->interested);
|
||||
}
|
||||
|
||||
bool CompilationUnit::isBuiltinFile(clang::FileID fid) {
|
||||
bool CompilationUnit::is_builtin_file(clang::FileID fid) {
|
||||
auto path = file_path(fid);
|
||||
return path == "<built-in>" || path == "<command line>" || path == "<scratch space>";
|
||||
}
|
||||
@@ -246,6 +246,10 @@ clang::TranslationUnitDecl* CompilationUnit::tu() {
|
||||
return impl->instance->getASTContext().getTranslationUnitDecl();
|
||||
}
|
||||
|
||||
const std::vector<Diagnostic>& CompilationUnit::diagnostics() {
|
||||
return *impl->diagnostics;
|
||||
}
|
||||
|
||||
llvm::DenseMap<clang::FileID, Directive>& CompilationUnit::directives() {
|
||||
return impl->m_directives;
|
||||
}
|
||||
@@ -255,10 +259,6 @@ TemplateResolver& CompilationUnit::resolver() {
|
||||
return *impl->m_resolver;
|
||||
}
|
||||
|
||||
clang::Sema& CompilationUnit::sema() {
|
||||
return impl->instance->getSema();
|
||||
}
|
||||
|
||||
clang::ASTContext& CompilationUnit::context() {
|
||||
return impl->instance->getASTContext();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Compiler/CompilationUnit.h"
|
||||
#include "Compiler/Diagnostic.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
|
||||
@@ -39,6 +40,8 @@ struct CompilationUnit::Impl {
|
||||
llvm::BumpPtrAllocator pathStorage;
|
||||
|
||||
std::vector<clang::Decl*> top_level_decls;
|
||||
|
||||
std::shared_ptr<std::vector<Diagnostic>> diagnostics;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -2,17 +2,14 @@
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticIDs.h"
|
||||
#include "clang/Basic/AllDiagnostics.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
void DiagnosticCollector::BeginSourceFile(const clang::LangOptions& Opts,
|
||||
const clang::Preprocessor* PP) {
|
||||
|
||||
};
|
||||
|
||||
const char* getDiagnosticCode(unsigned ID) {
|
||||
llvm::StringRef Diagnostic::diagnostic_code(std::uint32_t ID) {
|
||||
switch(ID) {
|
||||
#define DIAG(ENUM, \
|
||||
CLASS, \
|
||||
@@ -38,7 +35,7 @@ const char* getDiagnosticCode(unsigned ID) {
|
||||
#include "clang/Basic/DiagnosticSemaKinds.inc"
|
||||
#include "clang/Basic/DiagnosticSerializationKinds.inc"
|
||||
#undef DIAG
|
||||
default: return nullptr;
|
||||
default: return llvm::StringRef();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,31 +109,76 @@ void dumpArg(clang::DiagnosticsEngine::ArgumentKind kind, std::uint64_t value) {
|
||||
llvm::outs() << "\n";
|
||||
}
|
||||
|
||||
void DiagnosticCollector::HandleDiagnostic(clang::DiagnosticsEngine::Level level,
|
||||
const clang::Diagnostic& diagnostic) {
|
||||
llvm::SmallString<128> message;
|
||||
diagnostic.FormatDiagnostic(message);
|
||||
// diagnostic.getLocation();
|
||||
// fmt::print(fg(fmt::color::red),
|
||||
// "[Diagnostic, kind: {}, message: {}]\n",
|
||||
// refl::enum_name(level),
|
||||
// message.str().str());
|
||||
diagnostic.getLocation().dump(diagnostic.getDiags()->getSourceManager());
|
||||
// get diagnostic text.
|
||||
auto id = diagnostic.getID();
|
||||
llvm::outs() << getDiagnosticCode(id) << "\n";
|
||||
// llvm::outs() << diagnostic.getDiags()->getDiagnosticIDs()->getDescription(id) << "\n";
|
||||
// Checks whether a location is within a half-open range.
|
||||
// Note that clang also uses closed source ranges, which this can't handle!
|
||||
bool locationInRange(clang::SourceLocation L,
|
||||
clang::CharSourceRange R,
|
||||
const clang::SourceManager& M) {
|
||||
assert(R.isCharRange());
|
||||
if(!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
|
||||
M.getFileID(R.getBegin()) != M.getFileID(L))
|
||||
return false;
|
||||
return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
|
||||
}
|
||||
|
||||
// dumpArg(diagnostic.getArgKind(0), diagnostic.getRawArg(0));
|
||||
class DiagnosticCollector : public clang::DiagnosticConsumer {
|
||||
public:
|
||||
DiagnosticCollector(std::shared_ptr<std::vector<Diagnostic>> diagnostics) :
|
||||
diagnostics(diagnostics) {}
|
||||
|
||||
// FIXME:
|
||||
// use DiagnosticEngine::SetArgToStringFn to set a custom function to convert arguments to
|
||||
// strings. Support markdown diagnostic in LSP 3.18. allow complex type to display in markdown
|
||||
// code block.
|
||||
static DiagnosticLevel diagnostic_level(clang::DiagnosticsEngine::Level level) {
|
||||
switch(level) {
|
||||
case clang::DiagnosticsEngine::Ignored: return DiagnosticLevel::Ignored;
|
||||
case clang::DiagnosticsEngine::Note: return DiagnosticLevel::Note;
|
||||
case clang::DiagnosticsEngine::Remark: return DiagnosticLevel::Remark;
|
||||
case clang::DiagnosticsEngine::Warning: return DiagnosticLevel::Warning;
|
||||
case clang::DiagnosticsEngine::Error: return DiagnosticLevel::Error;
|
||||
case clang::DiagnosticsEngine::Fatal: return DiagnosticLevel::Fatal;
|
||||
default: return DiagnosticLevel::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
void BeginSourceFile(const clang::LangOptions& Opts, const clang::Preprocessor* PP) override {}
|
||||
|
||||
void HandleDiagnostic(clang::DiagnosticsEngine::Level level,
|
||||
const clang::Diagnostic& raw_diagnostic) override {
|
||||
|
||||
auto& diagnostic = diagnostics->emplace_back();
|
||||
diagnostic.id = raw_diagnostic.getID();
|
||||
diagnostic.level = diagnostic_level(level);
|
||||
|
||||
llvm::SmallString<256> message;
|
||||
raw_diagnostic.FormatDiagnostic(message);
|
||||
diagnostic.message = message.str();
|
||||
|
||||
auto location = raw_diagnostic.getLocation();
|
||||
if(location.isInvalid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& SM = raw_diagnostic.getDiags()->getSourceManager();
|
||||
for(auto& range: raw_diagnostic.getRanges()) {
|
||||
if(locationInRange(raw_diagnostic.getLocation(), range, SM)) {
|
||||
diagnostic.range = range.getAsRange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// use DiagnosticEngine::SetArgToStringFn to set a custom function to convert arguments to
|
||||
// strings. Support markdown diagnostic in LSP 3.18. allow complex type to display in
|
||||
// markdown code block.
|
||||
}
|
||||
|
||||
void EndSourceFile() override {}
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::vector<Diagnostic>> diagnostics;
|
||||
};
|
||||
|
||||
void DiagnosticCollector::EndSourceFile() {
|
||||
|
||||
};
|
||||
clang::DiagnosticConsumer*
|
||||
Diagnostic::create(std::shared_ptr<std::vector<Diagnostic>> diagnostics) {
|
||||
return new DiagnosticCollector(diagnostics);
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -13,12 +13,16 @@ std::string scanModuleName(CompilationParams& params) {
|
||||
langOpts.Modules = true;
|
||||
langOpts.CPlusPlus20 = true;
|
||||
|
||||
/// FIXME: Figure out main file from command line.
|
||||
assert(params.buffers.size() == 1);
|
||||
auto content = params.buffers.begin()->second->getBuffer();
|
||||
|
||||
/// We use raw mode of lexer to avoid the preprocessor.
|
||||
clang::Lexer lexer(clang::SourceLocation(),
|
||||
langOpts,
|
||||
params.content.begin(),
|
||||
params.content.begin(),
|
||||
params.content.end());
|
||||
content.begin(),
|
||||
content.begin(),
|
||||
content.end());
|
||||
|
||||
/// Whether we are in a condition directive.
|
||||
bool isInDirective = false;
|
||||
@@ -104,7 +108,7 @@ std::expected<ModuleInfo, std::string> scanModule(CompilationParams& params) {
|
||||
return std::unexpected(unit.error());
|
||||
}
|
||||
|
||||
for(auto& import: unit->directives()[unit->getInterestedFile()].imports) {
|
||||
for(auto& import: unit->directives()[unit->interested_file()].imports) {
|
||||
info.mods.emplace_back(import.name);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ std::vector<CompletionItem> codeCompletion(CompilationParams& params,
|
||||
const config::CodeCompletionOption& option) {
|
||||
auto& [file, offset] = params.completion;
|
||||
auto consumer = new CodeCompletionCollector(offset);
|
||||
if(auto info = compile(params, consumer)) {
|
||||
if(auto info = complete(params, consumer)) {
|
||||
return consumer->dump();
|
||||
/// TODO: Handle error here.
|
||||
} else {
|
||||
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
|
||||
auto buildForFile(CompilationUnit& unit) {
|
||||
TraverseTranslationUnitDecl(unit.tu());
|
||||
collectDrectives(unit.directives()[unit.getInterestedFile()]);
|
||||
collectDrectives(unit.directives()[unit.interested_file()]);
|
||||
std::ranges::sort(result, refl::less);
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
}
|
||||
|
||||
auto buildForFile() {
|
||||
highlight(unit.getInterestedFile());
|
||||
highlight(unit.interested_file());
|
||||
run();
|
||||
merge(result);
|
||||
return std::move(result);
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
|
||||
SemanticTokens semanticTokens(CompilationUnit& unit) {
|
||||
SemanticTokensCollector collector(unit, true);
|
||||
collector.highlight(unit.getInterestedFile());
|
||||
collector.highlight(unit.interested_file());
|
||||
collector.run();
|
||||
collector.merge(collector.result);
|
||||
return std::move(collector.result);
|
||||
|
||||
@@ -69,7 +69,7 @@ std::vector<SignatureHelpItem> signatureHelp(CompilationParams& params,
|
||||
const config::SignatureHelpOption& option) {
|
||||
std::vector<SignatureHelpItem> items;
|
||||
auto consumer = new SignatureHelpCollector({});
|
||||
if(auto info = compile(params, consumer)) {}
|
||||
if(auto info = complete(params, consumer)) {}
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ class IndexBuilder : public Indices, public SemanticVisitor<IndexBuilder> {
|
||||
public:
|
||||
IndexBuilder(CompilationUnit& unit) : SemanticVisitor(unit, false) {
|
||||
tu_index = std::make_unique<TUIndex>();
|
||||
tu_index->path = unit.file_path(unit.getInterestedFile());
|
||||
tu_index->content = unit.file_content(unit.getInterestedFile());
|
||||
tu_index->path = unit.file_path(unit.interested_file());
|
||||
tu_index->content = unit.file_content(unit.interested_file());
|
||||
tu_index->graph = IncludeGraph::from(unit);
|
||||
}
|
||||
|
||||
RawIndex& getIndex(clang::FileID fid) {
|
||||
if(fid == unit.getInterestedFile()) {
|
||||
if(fid == unit.interested_file()) {
|
||||
return *tu_index;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ async::Task<> Indexer::index(CompilationUnit& unit) {
|
||||
|
||||
async::Task<> Indexer::index(llvm::StringRef file) {
|
||||
CompilationParams params;
|
||||
params.srcPath = file;
|
||||
params.command = database.getCommand(file);
|
||||
|
||||
auto AST = co_await async::submit([&] { return compile(params); });
|
||||
|
||||
@@ -55,8 +55,7 @@ async::Task<json::Value> Scheduler::completion(std::string path, std::uint32_t o
|
||||
/// Set compilation params ... .
|
||||
CompilationParams params;
|
||||
params.command = database.getCommand(path);
|
||||
params.srcPath = path;
|
||||
params.content = openFile->content;
|
||||
params.add_remapped_file(path, openFile->content);
|
||||
params.pch = {PCH->path, PCH->preamble.size()};
|
||||
params.completion = {path, offset};
|
||||
|
||||
@@ -105,11 +104,9 @@ async::Task<> Scheduler::buildPCH(std::string path, std::string content) {
|
||||
std::uint32_t bound,
|
||||
std::string content) -> async::Task<> {
|
||||
CompilationParams params;
|
||||
params.srcPath = path;
|
||||
params.command = scheduler.database.getCommand(path);
|
||||
params.content = content;
|
||||
params.bound = bound;
|
||||
params.outPath = path::join(config::index.dir, path::filename(path) + ".pch");
|
||||
params.add_remapped_file(path, content, bound);
|
||||
|
||||
PCHInfo info;
|
||||
auto result = co_await async::submit([&] { return compile(params, info); });
|
||||
@@ -164,9 +161,8 @@ async::Task<> Scheduler::buildAST(std::string path, std::string content) {
|
||||
}
|
||||
|
||||
CompilationParams params;
|
||||
params.srcPath = path;
|
||||
params.command = database.getCommand(path);
|
||||
params.content = content;
|
||||
params.add_remapped_file(path, content);
|
||||
params.pch = {PCH->path, PCH->preamble.size()};
|
||||
|
||||
/// Check result
|
||||
|
||||
Reference in New Issue
Block a user