some fix and update.
This commit is contained in:
@@ -42,18 +42,6 @@ int main(int argc, const char** argv) {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
if(clang::FileManager* manager = instance->createFileManager()) {
|
||||
instance->createSourceManager(*manager);
|
||||
} else {
|
||||
llvm::errs() << "Failed to create file manager\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
instance->createPreprocessor(clang::TranslationUnitKind::TU_Complete);
|
||||
|
||||
// ASTContent is necessary for SemanticAnalysis
|
||||
instance->createASTContext();
|
||||
|
||||
clang::SyntaxOnlyAction action;
|
||||
|
||||
if(!action.BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
#include <Clang/Clang.h>
|
||||
#include <clang/Lex/PreprocessorOptions.h>
|
||||
|
||||
// clang 的 CodeCompletion 提供的功能非常有限,无法直接区分当前的
|
||||
// clang 的 CodeCompletion 提供的功能非常有限,无法获取当前 Completion 的 scope
|
||||
// 而获取 scope 是非常重要的一个功能,有了它我们可以做更多事情,比如只把 ...sizeof 显示在可变模板参数的语境下
|
||||
// 又或者根据函数名的语境不同(定义和调用)执行不同的补全逻辑,定义的时候就自动补全参数,调用的时候就不补全
|
||||
// 我们只能通过一些 hack 的手段来做这个事情了,首先使用 TokenWatcher 可以获取到所有的 Token
|
||||
// 同样我们可以获取到最终的 tu,
|
||||
|
||||
// TODO: 检查 SemaCodeCompletion.cpp,看看能不能把当前代码补全的 scope 拿到,当然在这之前,先尝试前面那种 hack
|
||||
// 的 方式,看看能不能同样拿到这些信息,反正 token 位置和最后的语法树都是有的 由于要改 clang
|
||||
// 源码,所以这不是一个高优先级的任务 ...
|
||||
|
||||
class CodeCompleteConsumer : public clang::CodeCompleteConsumer {
|
||||
private:
|
||||
@@ -23,6 +32,9 @@ public:
|
||||
auto contexts = Context.getVisitedContexts();
|
||||
for(auto c: contexts) {
|
||||
llvm::outs() << " Kind: " << c->getDeclKindName() << "\n";
|
||||
for(auto d: c->decls()) {
|
||||
d->dump();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::outs() << "code completion results:\n";
|
||||
@@ -120,6 +132,9 @@ int main(int argc, const char** argv) {
|
||||
codeCompletionAt.Line = std::stoi(argv[2]);
|
||||
codeCompletionAt.Column = std::stoi(argv[3]);
|
||||
|
||||
clang::PreprocessorOptions& popts = invocation->getPreprocessorOpts();
|
||||
popts.DetailedRecord = true;
|
||||
|
||||
instance->setInvocation(std::move(invocation));
|
||||
|
||||
if(!instance->createTarget()) {
|
||||
@@ -127,18 +142,6 @@ int main(int argc, const char** argv) {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
if(clang::FileManager* manager = instance->createFileManager()) {
|
||||
instance->createSourceManager(*manager);
|
||||
} else {
|
||||
llvm::errs() << "Failed to create file manager\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
instance->createPreprocessor(clang::TranslationUnitKind::TU_Complete);
|
||||
|
||||
// ASTContent is necessary for SemanticAnalysis
|
||||
instance->createASTContext();
|
||||
|
||||
/// NOTICE:
|
||||
instance->setCodeCompletionConsumer(new CodeCompleteConsumer());
|
||||
|
||||
@@ -151,7 +154,9 @@ int main(int argc, const char** argv) {
|
||||
|
||||
auto& pp = instance->getPreprocessor();
|
||||
pp.setTokenWatcher([&pp](const clang::Token& token) {
|
||||
llvm::outs() << "token: " << pp.getSpelling(token) << " kind: " << token.getName() << "\n";
|
||||
if(!token.isAnnotation()) {
|
||||
// llvm::outs() << "token: " << pp.getSpelling(token) << " kind: " << token.getName() << "\n";
|
||||
}
|
||||
});
|
||||
|
||||
if(auto error = action.Execute()) {
|
||||
@@ -160,7 +165,7 @@ int main(int argc, const char** argv) {
|
||||
}
|
||||
|
||||
auto tu = instance->getASTContext().getTranslationUnitDecl();
|
||||
tu->dump();
|
||||
// tu->dump();
|
||||
|
||||
action.EndSourceFile();
|
||||
}
|
||||
|
||||
@@ -1,54 +1,44 @@
|
||||
#include <Clang/Clang.h>
|
||||
#include <filesystem>
|
||||
#include <clang/Basic/Diagnostic.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Frontend/TextDiagnosticPrinter.h>
|
||||
#include <clang/Sema/Sema.h>
|
||||
#include <clang/Tooling/CompilationDatabase.h>
|
||||
#include <clang/Tooling/Syntax/Tokens.h>
|
||||
#include <clang/Lex/PreprocessorOptions.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
assert(argc == 2 && "Usage: Preamble <source-file>");
|
||||
llvm::outs() << "running Preamble...\n";
|
||||
|
||||
auto instance = std::make_unique<clang::CompilerInstance>();
|
||||
|
||||
clang::DiagnosticIDs* ids = new clang::DiagnosticIDs();
|
||||
clang::DiagnosticOptions* diag_opts = new clang::DiagnosticOptions();
|
||||
clang::DiagnosticConsumer* consumer = new clang::TextDiagnosticPrinter(llvm::errs(), diag_opts);
|
||||
clang::DiagnosticsEngine* engine = new clang::DiagnosticsEngine(ids, diag_opts, consumer);
|
||||
instance->setDiagnostics(engine);
|
||||
|
||||
auto invocation =
|
||||
std::make_shared<clang::CompilerInvocation>(std::make_shared<clang::PCHContainerOperations>());
|
||||
std::vector<const char*> args = {
|
||||
"/home/ykiko/Project/C++/clice/external/llvm/bin/clang++",
|
||||
"-Xclang",
|
||||
"-no-round-trip-args",
|
||||
"-std=c++20",
|
||||
"-Wno-everything",
|
||||
argv[1],
|
||||
"-c",
|
||||
};
|
||||
|
||||
invocation = clang::createInvocation(args, {});
|
||||
auto buildPreamble(std::vector<const char*> args, const char* path) {
|
||||
auto invocation = clang::createInvocation(args, {});
|
||||
|
||||
// from filepath: llvm::MemoryBuffer::getFile
|
||||
// from content: llvm::MemoryBuffer::getMemBuffer(content);
|
||||
auto tmp = llvm::MemoryBuffer::getFile(argv[1]);
|
||||
auto tmp = llvm::MemoryBuffer::getFile(path);
|
||||
if(auto error = tmp.getError()) {
|
||||
llvm::errs() << "Failed to get file: " << error.message() << "\n";
|
||||
std::terminate();
|
||||
}
|
||||
llvm::MemoryBuffer* buffer = tmp->get();
|
||||
llvm::MemoryBuffer* buffer = tmp->release();
|
||||
|
||||
// compute preamble bounds, if MaxLines set to false(0), it means not to limit the number of lines
|
||||
auto bounds = clang::ComputePreambleBounds({}, *buffer, false);
|
||||
auto bounds = clang::ComputePreambleBounds(invocation->getLangOpts(), *buffer, false);
|
||||
|
||||
auto VFS = llvm::vfs::getRealFileSystem();
|
||||
// if(auto error = VFS->setCurrentWorkingDirectory(fs::path(argv[1]).parent_path().string())) {
|
||||
// llvm::errs() << "Failed to set current working directory: " << error.message() << "\n";
|
||||
// }
|
||||
// create diagnostic engine
|
||||
clang::DiagnosticsEngine* engine = new clang::DiagnosticsEngine(
|
||||
new clang::DiagnosticIDs(),
|
||||
new clang::DiagnosticOptions(),
|
||||
new clang::TextDiagnosticPrinter(llvm::errs(), new clang::DiagnosticOptions()));
|
||||
|
||||
// if store the preamble in memory, if not, store it in a file(storagePath)
|
||||
bool storeInMemory = true;
|
||||
std::string storagePath = (fs::path(argv[0]).parent_path()).string();
|
||||
bool storeInMemory = false;
|
||||
std::string storagePath = (fs::path(path).parent_path() / "build").string();
|
||||
|
||||
auto VFS = llvm::vfs::getRealFileSystem();
|
||||
if(auto error = VFS->setCurrentWorkingDirectory(storagePath)) {
|
||||
llvm::errs() << error.message() << "\n";
|
||||
}
|
||||
|
||||
// use to collect information in the process of building preamble, such as include files and macros
|
||||
// TODO: inherit from clang::PreambleCallbacks and collect the information
|
||||
@@ -59,10 +49,10 @@ int main(int argc, const char** argv) {
|
||||
buffer,
|
||||
bounds,
|
||||
*engine,
|
||||
VFS,
|
||||
llvm::vfs::getRealFileSystem(),
|
||||
std::make_shared<clang::PCHContainerOperations>(),
|
||||
storeInMemory,
|
||||
"",
|
||||
storagePath,
|
||||
callbacks);
|
||||
|
||||
if(auto error = preamble.getError()) {
|
||||
@@ -70,7 +60,39 @@ int main(int argc, const char** argv) {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
return preamble;
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
assert(argc == 2 && "Usage: Preamble <source-file>");
|
||||
llvm::outs() << "running Preamble...\n";
|
||||
|
||||
std::vector<const char*> args = {
|
||||
"/home/ykiko/Project/C++/clice/external/llvm/bin/clang++",
|
||||
"-Xclang",
|
||||
"-no-round-trip-args",
|
||||
"-std=c++20",
|
||||
"-Wno-everything",
|
||||
argv[1],
|
||||
};
|
||||
|
||||
auto preamble = buildPreamble(args, argv[1]);
|
||||
|
||||
auto instance = std::make_unique<clang::CompilerInstance>();
|
||||
|
||||
auto invocation = std::make_shared<clang::CompilerInvocation>();
|
||||
invocation = clang::createInvocation(args, {});
|
||||
|
||||
auto tmp = llvm::MemoryBuffer::getFile(argv[1]);
|
||||
if(auto error = tmp.getError()) {
|
||||
llvm::errs() << "Failed to get file: " << error.message() << "\n";
|
||||
std::terminate();
|
||||
}
|
||||
llvm::MemoryBuffer* buffer = tmp->release();
|
||||
|
||||
auto VFS = llvm::vfs::getRealFileSystem();
|
||||
auto bounds = clang::ComputePreambleBounds(invocation->getLangOpts(), *buffer, false);
|
||||
|
||||
// check if the preamble can be reused
|
||||
if(preamble->CanReuse(*invocation, *buffer, bounds, *VFS)) {
|
||||
llvm::outs() << "Resued preamble\n";
|
||||
@@ -80,26 +102,19 @@ int main(int argc, const char** argv) {
|
||||
|
||||
instance->setInvocation(std::move(invocation));
|
||||
|
||||
instance->createDiagnostics(
|
||||
new clang::TextDiagnosticPrinter(llvm::errs(), new clang::DiagnosticOptions()),
|
||||
true);
|
||||
|
||||
if(!instance->createTarget()) {
|
||||
llvm::errs() << "Failed to create target\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
if(clang::FileManager* manager = instance->createFileManager()) {
|
||||
instance->createSourceManager(*manager);
|
||||
} else {
|
||||
llvm::errs() << "Failed to create file manager\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
instance->createPreprocessor(clang::TranslationUnitKind::TU_Complete);
|
||||
|
||||
// ASTContent is necessary for SemanticAnalysis
|
||||
instance->createASTContext();
|
||||
|
||||
clang::SyntaxOnlyAction action;
|
||||
|
||||
if(!action.BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
|
||||
auto& mainInput = instance->getFrontendOpts().Inputs[0];
|
||||
if(!action.BeginSourceFile(*instance, mainInput)) {
|
||||
llvm::errs() << "Failed to begin source file\n";
|
||||
std::terminate();
|
||||
}
|
||||
@@ -109,5 +124,6 @@ int main(int argc, const char** argv) {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
instance->getASTContext().getTranslationUnitDecl()->dump();
|
||||
action.EndSourceFile();
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ int main(int argc, const char** argv) {
|
||||
|
||||
auto invocation = std::make_shared<clang::CompilerInvocation>();
|
||||
std::vector<const char*> args = {
|
||||
"/home/ykiko/Project/C++/clice/external/llvm/bin/clang++",
|
||||
"/usr/local/bin/clang++",
|
||||
"-x",
|
||||
"c++",
|
||||
"-Xclang",
|
||||
"-no-round-trip-args",
|
||||
"-std=c++20",
|
||||
|
||||
Reference in New Issue
Block a user