diff --git a/src/clang_tu.cc b/src/clang_tu.cc index 8fb8403f..f7fb6d0f 100644 --- a/src/clang_tu.cc +++ b/src/clang_tu.cc @@ -81,7 +81,7 @@ Range FromTokenRangeDefaulted(const SourceManager &SM, const LangOptions &Lang, } std::unique_ptr -BuildCompilerInvocation(std::vector args, +BuildCompilerInvocation(const std::string &main, std::vector args, IntrusiveRefCntPtr VFS) { std::string save = "-resource-dir=" + g_config->clang.resourceDir; args.push_back(save.c_str()); @@ -94,6 +94,9 @@ BuildCompilerInvocation(std::vector args, CI->getDiagnosticOpts().IgnoreWarnings = true; CI->getFrontendOpts().DisableFree = 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; } diff --git a/src/clang_tu.hh b/src/clang_tu.hh index f301334f..4adc4632 100644 --- a/src/clang_tu.hh +++ b/src/clang_tu.hh @@ -39,7 +39,8 @@ Range FromTokenRangeDefaulted(const clang::SourceManager &SM, Range range); std::unique_ptr -BuildCompilerInvocation(std::vector args, +BuildCompilerInvocation(const std::string &main, + std::vector args, llvm::IntrusiveRefCntPtr VFS); const char *ClangBuiltinTypeName(int); diff --git a/src/indexer.cc b/src/indexer.cc index d33299dc..d8631692 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -1217,14 +1217,15 @@ void Init() { std::vector> 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 &args, const std::vector> &remapped, bool &ok) { ok = true; auto PCH = std::make_shared(); llvm::IntrusiveRefCntPtr FS = llvm::vfs::getRealFileSystem(); - std::shared_ptr CI = BuildCompilerInvocation(args, FS); + std::shared_ptr CI = + BuildCompilerInvocation(main, args, FS); // e.g. .s if (!CI) return {}; @@ -1234,35 +1235,13 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs, CI->getLangOpts()->CommentOpts.ParseAllComments = g_config->index.comments > 1; CI->getLangOpts()->RetainCommentsFromSystemHeaders = true; - std::string buf = wfiles->GetContent(file); + std::string buf = wfiles->GetContent(main); std::vector> Bufs; - if (buf.size()) { - // If there is a completion session, reuse its preamble if exists. - bool done_remap = false; -#if 0 - std::shared_ptr 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 + if (buf.size()) for (auto &[filename, content] : remapped) { - if (filename == file && done_remap) - continue; Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(content)); - CI->getPreprocessorOpts().addRemappedFile( - filename == file ? CI->getFrontendOpts().Inputs[0].getFile() - : StringRef(filename), - Bufs.back().get()); + CI->getPreprocessorOpts().addRemappedFile(filename, Bufs.back().get()); } - } DiagnosticConsumer DC; auto Clang = std::make_unique(PCH); @@ -1291,20 +1270,20 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs, { llvm::CrashRecoveryContext CRC; auto parse = [&]() { - if (!Action->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) - return; - if (!Action->Execute()) - return; - Action->EndSourceFile(); - ok = true; - }; + if (!Action->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) + return; + if (!Action->Execute()) + return; + Action->EndSourceFile(); + ok = true; + }; if (!CRC.RunSafely(parse)) { - LOG_S(ERROR) << "clang crashed for " << file; + LOG_S(ERROR) << "clang crashed for " << main; return {}; } } if (!ok) { - LOG_S(ERROR) << "failed to index " << file; + LOG_S(ERROR) << "failed to index " << main; return {}; } for (auto &Buf : Bufs) @@ -1315,7 +1294,7 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs, if (!it.second.db) continue; std::unique_ptr &entry = it.second.db; - entry->import_file = file; + entry->import_file = main; entry->args = args; for (auto &[_, it] : entry->uid2lid_and_path) entry->lid2path.emplace_back(it.first, std::move(it.second)); diff --git a/src/pipeline.cc b/src/pipeline.cc index c7b8e204..d4a3f788 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include 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(); 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; if (changed) LOG_S(INFO) << "args changed for " << path @@ -195,7 +198,8 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles, } // 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()) return true; if (request.args.size()) diff --git a/src/project.cc b/src/project.cc index b4347174..c96eac1e 100644 --- a/src/project.cc +++ b/src/project.cc @@ -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) { Project::Folder *best_folder = nullptr; const Entry *best = nullptr; std::lock_guard lock(mtx); 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); if (it != folder.path2entry_index.end()) { Project::Entry &entry = folder.entries[it->second]; - if (!must_exist || entry.filename == path) + if (can_redirect || entry.filename == path) return entry; + if (entry.compdb_size) { + best_folder = &folder; + best = &entry; + } + break; } } @@ -471,7 +478,7 @@ out: best_folder = &folder; } } - } + } } ret.is_inferred = true; @@ -485,14 +492,6 @@ out: ret.root = best->root; ret.directory = best->directory; 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); if (extra && extra->size()) ret.args.insert(ret.args.end(), extra->begin() + 1, extra->end()); diff --git a/src/project.hh b/src/project.hh index 0434f402..472cb32a 100644 --- a/src/project.hh +++ b/src/project.hh @@ -56,7 +56,7 @@ struct Project { // Lookup the CompilationEntry for |filename|. If no entry was found this // 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 // that is not in the compilation_database.json make sure those changes diff --git a/src/sema_manager.cc b/src/sema_manager.cc index 006c82be..afbc3a6f 100644 --- a/src/sema_manager.cc +++ b/src/sema_manager.cc @@ -409,7 +409,7 @@ void *PreambleMain(void *manager_) { IntrusiveRefCntPtr FS = stat_cache->Producer(session->FS); if (std::unique_ptr CI = - BuildCompilerInvocation(session->file.args, FS)) + BuildCompilerInvocation(task.path, session->file.args, FS)) BuildPreamble(*session, *CI, FS, task, std::move(stat_cache)); if (task.from_diag) { @@ -449,7 +449,7 @@ void *CompletionMain(void *manager_) { IntrusiveRefCntPtr FS = preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS; std::unique_ptr CI = - BuildCompilerInvocation(session->file.args, FS); + BuildCompilerInvocation(task->path, session->file.args, FS); if (!CI) continue; auto &FOpts = CI->getFrontendOpts(); @@ -551,7 +551,7 @@ void *DiagnosticMain(void *manager_) { } std::unique_ptr CI = - BuildCompilerInvocation(session->file.args, FS); + BuildCompilerInvocation(task.path, session->file.args, FS); if (!CI) continue; // 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 session = sessions.Get(path); if (!session) { session = std::make_shared( - project_->FindEntry(path, true), wfiles, PCH); + project_->FindEntry(path, false, false), wfiles, PCH); std::string line; if (LOG_V_ENABLED(1)) { line = "\n ";