Adjust FrontendOpts.Inputs[0] for inferred files

This commit is contained in:
Fangrui Song 2018-12-23 21:22:51 -08:00
parent 52e0289245
commit dd74d03cfc
7 changed files with 43 additions and 57 deletions

View File

@ -81,7 +81,7 @@ Range FromTokenRangeDefaulted(const SourceManager &SM, const LangOptions &Lang,
} }
std::unique_ptr<CompilerInvocation> std::unique_ptr<CompilerInvocation>
BuildCompilerInvocation(std::vector<const char *> args, BuildCompilerInvocation(const std::string &main, std::vector<const char *> args,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) { IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
std::string save = "-resource-dir=" + g_config->clang.resourceDir; std::string save = "-resource-dir=" + g_config->clang.resourceDir;
args.push_back(save.c_str()); args.push_back(save.c_str());
@ -94,6 +94,9 @@ BuildCompilerInvocation(std::vector<const char *> args,
CI->getDiagnosticOpts().IgnoreWarnings = true; CI->getDiagnosticOpts().IgnoreWarnings = true;
CI->getFrontendOpts().DisableFree = false; CI->getFrontendOpts().DisableFree = false;
CI->getLangOpts()->SpellChecking = false; CI->getLangOpts()->SpellChecking = false;
auto &IS = CI->getFrontendOpts().Inputs;
if (IS.size())
IS[0] = FrontendInputFile(main, IS[0].getKind(), IS[0].isSystem());
} }
return CI; return CI;
} }

View File

@ -39,7 +39,8 @@ Range FromTokenRangeDefaulted(const clang::SourceManager &SM,
Range range); Range range);
std::unique_ptr<clang::CompilerInvocation> std::unique_ptr<clang::CompilerInvocation>
BuildCompilerInvocation(std::vector<const char *> args, BuildCompilerInvocation(const std::string &main,
std::vector<const char *> args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS); llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS);
const char *ClangBuiltinTypeName(int); const char *ClangBuiltinTypeName(int);

View File

@ -1217,14 +1217,15 @@ void Init() {
std::vector<std::unique_ptr<IndexFile>> std::vector<std::unique_ptr<IndexFile>>
Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs, Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
const std::string &opt_wdir, const std::string &file, const std::string &opt_wdir, const std::string &main,
const std::vector<const char *> &args, const std::vector<const char *> &args,
const std::vector<std::pair<std::string, std::string>> &remapped, const std::vector<std::pair<std::string, std::string>> &remapped,
bool &ok) { bool &ok) {
ok = true; ok = true;
auto PCH = std::make_shared<PCHContainerOperations>(); auto PCH = std::make_shared<PCHContainerOperations>();
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = llvm::vfs::getRealFileSystem(); llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = llvm::vfs::getRealFileSystem();
std::shared_ptr<CompilerInvocation> CI = BuildCompilerInvocation(args, FS); std::shared_ptr<CompilerInvocation> CI =
BuildCompilerInvocation(main, args, FS);
// e.g. .s // e.g. .s
if (!CI) if (!CI)
return {}; return {};
@ -1234,35 +1235,13 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
CI->getLangOpts()->CommentOpts.ParseAllComments = CI->getLangOpts()->CommentOpts.ParseAllComments =
g_config->index.comments > 1; g_config->index.comments > 1;
CI->getLangOpts()->RetainCommentsFromSystemHeaders = true; CI->getLangOpts()->RetainCommentsFromSystemHeaders = true;
std::string buf = wfiles->GetContent(file); std::string buf = wfiles->GetContent(main);
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs; std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
if (buf.size()) { if (buf.size())
// If there is a completion session, reuse its preamble if exists.
bool done_remap = false;
#if 0
std::shared_ptr<CompletionSession> session =
manager->TryGetSession(file, false, false);
if (session)
if (auto preamble = session->GetPreamble()) {
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(buf));
auto Bounds = ComputePreambleBounds(*CI->getLangOpts(), Bufs.back().get(), 0);
if (preamble->Preamble.CanReuse(*CI, Bufs.back().get(), Bounds,
FS.get())) {
preamble->Preamble.AddImplicitPreamble(*CI, FS, Bufs.back().get());
done_remap = true;
}
}
#endif
for (auto &[filename, content] : remapped) { for (auto &[filename, content] : remapped) {
if (filename == file && done_remap)
continue;
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(content)); Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(content));
CI->getPreprocessorOpts().addRemappedFile( CI->getPreprocessorOpts().addRemappedFile(filename, Bufs.back().get());
filename == file ? CI->getFrontendOpts().Inputs[0].getFile()
: StringRef(filename),
Bufs.back().get());
} }
}
DiagnosticConsumer DC; DiagnosticConsumer DC;
auto Clang = std::make_unique<CompilerInstance>(PCH); auto Clang = std::make_unique<CompilerInstance>(PCH);
@ -1291,20 +1270,20 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
{ {
llvm::CrashRecoveryContext CRC; llvm::CrashRecoveryContext CRC;
auto parse = [&]() { auto parse = [&]() {
if (!Action->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) if (!Action->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
return; return;
if (!Action->Execute()) if (!Action->Execute())
return; return;
Action->EndSourceFile(); Action->EndSourceFile();
ok = true; ok = true;
}; };
if (!CRC.RunSafely(parse)) { if (!CRC.RunSafely(parse)) {
LOG_S(ERROR) << "clang crashed for " << file; LOG_S(ERROR) << "clang crashed for " << main;
return {}; return {};
} }
} }
if (!ok) { if (!ok) {
LOG_S(ERROR) << "failed to index " << file; LOG_S(ERROR) << "failed to index " << main;
return {}; return {};
} }
for (auto &Buf : Bufs) for (auto &Buf : Bufs)
@ -1315,7 +1294,7 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
if (!it.second.db) if (!it.second.db)
continue; continue;
std::unique_ptr<IndexFile> &entry = it.second.db; std::unique_ptr<IndexFile> &entry = it.second.db;
entry->import_file = file; entry->import_file = main;
entry->args = args; entry->args = args;
for (auto &[_, it] : entry->uid2lid_and_path) for (auto &[_, it] : entry->uid2lid_and_path)
entry->lid2path.emplace_back(it.first, std::move(it.second)); entry->lid2path.emplace_back(it.first, std::move(it.second));

View File

@ -17,6 +17,7 @@
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <rapidjson/writer.h> #include <rapidjson/writer.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/Process.h> #include <llvm/Support/Process.h>
#include <llvm/Support/Threading.h> #include <llvm/Support/Threading.h>
using namespace llvm; using namespace llvm;
@ -110,9 +111,11 @@ bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
} }
} }
// For inferred files, allow -o a a.cc -> -o b b.cc
std::string stem = sys::path::stem(path);
bool changed = prev->args.size() != args.size(); bool changed = prev->args.size() != args.size();
for (size_t i = 0; !changed && i < args.size(); i++) for (size_t i = 0; !changed && i < args.size(); i++)
if (strcmp(prev->args[i], args[i])) if (strcmp(prev->args[i], args[i]) && sys::path::stem(args[i]) != stem)
changed = true; changed = true;
if (changed) if (changed)
LOG_S(INFO) << "args changed for " << path LOG_S(INFO) << "args changed for " << path
@ -195,7 +198,8 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
} }
// must_exist is currently unused. // must_exist is currently unused.
Project::Entry entry = project->FindEntry(request.path, false); Project::Entry entry =
project->FindEntry(request.path, true, request.must_exist);
if (request.must_exist && entry.filename.empty()) if (request.must_exist && entry.filename.empty())
return true; return true;
if (request.args.size()) if (request.args.size())

View File

@ -411,17 +411,24 @@ void Project::Load(const std::string &root) {
} }
} }
Project::Entry Project::FindEntry(const std::string &path, Project::Entry Project::FindEntry(const std::string &path, bool can_redirect,
bool must_exist) { bool must_exist) {
Project::Folder *best_folder = nullptr; Project::Folder *best_folder = nullptr;
const Entry *best = nullptr; const Entry *best = nullptr;
std::lock_guard lock(mtx); std::lock_guard lock(mtx);
for (auto &[root, folder] : root2folder) { for (auto &[root, folder] : root2folder) {
// The entry may have different filename but it doesn't matter when building
// CompilerInvocation. The main filename is specified separately.
auto it = folder.path2entry_index.find(path); auto it = folder.path2entry_index.find(path);
if (it != folder.path2entry_index.end()) { if (it != folder.path2entry_index.end()) {
Project::Entry &entry = folder.entries[it->second]; Project::Entry &entry = folder.entries[it->second];
if (!must_exist || entry.filename == path) if (can_redirect || entry.filename == path)
return entry; return entry;
if (entry.compdb_size) {
best_folder = &folder;
best = &entry;
}
break;
} }
} }
@ -471,7 +478,7 @@ out:
best_folder = &folder; best_folder = &folder;
} }
} }
} }
} }
ret.is_inferred = true; ret.is_inferred = true;
@ -485,14 +492,6 @@ out:
ret.root = best->root; ret.root = best->root;
ret.directory = best->directory; ret.directory = best->directory;
ret.args = best->args; ret.args = best->args;
std::string base_name = sys::path::filename(best->filename);
for (const char *&arg : ret.args) {
try {
if (arg == best->filename || sys::path::filename(arg) == base_name)
arg = Intern(path);
} catch (...) {
}
}
ret.args.resize(best->compdb_size); ret.args.resize(best->compdb_size);
if (extra && extra->size()) if (extra && extra->size())
ret.args.insert(ret.args.end(), extra->begin() + 1, extra->end()); ret.args.insert(ret.args.end(), extra->begin() + 1, extra->end());

View File

@ -56,7 +56,7 @@ struct Project {
// Lookup the CompilationEntry for |filename|. If no entry was found this // Lookup the CompilationEntry for |filename|. If no entry was found this
// will infer one based on existing project structure. // will infer one based on existing project structure.
Entry FindEntry(const std::string &path, bool can_be_inferred); Entry FindEntry(const std::string &path, bool can_redirect, bool must_exist);
// If the client has overridden the flags, or specified them for a file // If the client has overridden the flags, or specified them for a file
// that is not in the compilation_database.json make sure those changes // that is not in the compilation_database.json make sure those changes

View File

@ -409,7 +409,7 @@ void *PreambleMain(void *manager_) {
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
stat_cache->Producer(session->FS); stat_cache->Producer(session->FS);
if (std::unique_ptr<CompilerInvocation> CI = if (std::unique_ptr<CompilerInvocation> CI =
BuildCompilerInvocation(session->file.args, FS)) BuildCompilerInvocation(task.path, session->file.args, FS))
BuildPreamble(*session, *CI, FS, task, std::move(stat_cache)); BuildPreamble(*session, *CI, FS, task, std::move(stat_cache));
if (task.from_diag) { if (task.from_diag) {
@ -449,7 +449,7 @@ void *CompletionMain(void *manager_) {
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS; preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS;
std::unique_ptr<CompilerInvocation> CI = std::unique_ptr<CompilerInvocation> CI =
BuildCompilerInvocation(session->file.args, FS); BuildCompilerInvocation(task->path, session->file.args, FS);
if (!CI) if (!CI)
continue; continue;
auto &FOpts = CI->getFrontendOpts(); auto &FOpts = CI->getFrontendOpts();
@ -551,7 +551,7 @@ void *DiagnosticMain(void *manager_) {
} }
std::unique_ptr<CompilerInvocation> CI = std::unique_ptr<CompilerInvocation> CI =
BuildCompilerInvocation(session->file.args, FS); BuildCompilerInvocation(task.path, session->file.args, FS);
if (!CI) if (!CI)
continue; continue;
// If main file is a header, add -Wno-unused-function // If main file is a header, add -Wno-unused-function
@ -696,7 +696,7 @@ SemaManager::EnsureSession(const std::string &path, bool *created) {
std::shared_ptr<ccls::Session> session = sessions.Get(path); std::shared_ptr<ccls::Session> session = sessions.Get(path);
if (!session) { if (!session) {
session = std::make_shared<ccls::Session>( session = std::make_shared<ccls::Session>(
project_->FindEntry(path, true), wfiles, PCH); project_->FindEntry(path, false, false), wfiles, PCH);
std::string line; std::string line;
if (LOG_V_ENABLED(1)) { if (LOG_V_ENABLED(1)) {
line = "\n "; line = "\n ";