experimental/filesystem -> LLVM/Support/FileSystem.h; sparsepp -> DenseMap

This commit is contained in:
Fangrui Song 2018-05-13 13:30:24 -07:00
parent c81ca26a2e
commit 36729818c3
15 changed files with 116 additions and 110 deletions

3
.gitmodules vendored
View File

@ -4,9 +4,6 @@
[submodule "third_party/doctest"]
path = third_party/doctest
url = https://github.com/onqtam/doctest
[submodule "third_party/sparsepp"]
path = third_party/sparsepp
url = https://github.com/greg7mdp/sparsepp
[submodule "third_party/loguru"]
path = third_party/loguru
url = https://github.com/emilk/loguru

View File

@ -91,10 +91,9 @@ if(NOT SYSTEM_CLANG)
target_compile_options(ccls PRIVATE -nostdinc++ -cxx-isystem ${CLANG_ROOT}/include/c++/v1)
if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
# Don't use -stdlib=libc++ because while ccls is linked with libc++, bundled clang+llvm require libstdc++
target_link_libraries(ccls PRIVATE -L${CLANG_ROOT}/lib c++ c++experimental c++abi)
else()
# FreeBSD uses system libcxxrt.a and does not need libc++abi.
target_link_libraries(ccls PRIVATE -stdlib=libc++ -L${CLANG_ROOT}/lib c++experimental)
target_link_libraries(ccls PRIVATE -L${CLANG_ROOT}/lib c++ c++abi)
# FreeBSD defaults to -stdlib=libc++ and uses system libcxxrt.a
endif()
endif()
@ -121,25 +120,17 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin)
target_link_libraries(ccls PRIVATE -lc++experimental)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
if(NOT CLANG_USE_BUNDLED_LIBC++)
target_link_libraries(ccls PRIVATE -lstdc++fs)
endif()
# loguru calls dladdr
target_link_libraries(ccls PRIVATE ${CMAKE_DL_LIBS})
elseif(${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD)
# loguru::stacktrace_as_stdstring calls backtrace_symbols
# sparsepp/spp_memory.h uses libkvm
# src/platform_posix.cc uses libthr
find_package(Backtrace REQUIRED)
target_link_libraries(ccls PRIVATE ${Backtrace_LIBRARIES} kvm thr)
target_link_libraries(ccls PRIVATE ${Backtrace_LIBRARIES} thr)
if(SYSTEM_CLANG)
target_link_libraries(ccls PRIVATE c++experimental)
endif()
elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows)
# sparsepp/spp_memory.h uses LibPsapi
target_link_libraries(ccls PRIVATE Psapi)
endif()
### Definitions
@ -156,7 +147,6 @@ target_include_directories(ccls PRIVATE
src
third_party
third_party/rapidjson/include
third_party/sparsepp
third_party/loguru
third_party/doctest)

View File

@ -70,6 +70,7 @@ set(_Clang_REQUIRED_VARS Clang_LIBRARY Clang_INCLUDE_DIR Clang_EXECUTABLE
_Clang_find_library(Clang_LIBRARY clang)
_Clang_find_add_library(clangDriver)
_Clang_find_add_library(clangBasic)
_Clang_find_add_library(LLVMOption)
_Clang_find_add_library(LLVMSupport)
_Clang_find_add_library(LLVMDemangle)

View File

@ -1,10 +1,12 @@
#include "clang_complete.h"
#include "clang_utils.h"
#include "filesystem.hh"
#include "platform.h"
#include "timer.h"
#include "filesystem.hh"
using namespace llvm;
#include <loguru.hpp>
#include <algorithm>
@ -29,8 +31,9 @@ unsigned Flags() {
}
std::string StripFileType(const std::string& path) {
fs::path p(path);
return p.parent_path() / p.stem();
SmallString<128> Ret;
sys::path::append(Ret, sys::path::parent_path(path), sys::path::stem(path));
return Ret.str();
}
unsigned GetCompletionPriority(const CXCompletionString& str,

View File

@ -1,8 +1,10 @@
#include "clang_utils.h"
#include "filesystem.hh"
#include "platform.h"
#include "filesystem.hh"
using namespace llvm;
namespace {
lsRange GetLsRangeForFixIt(const CXSourceRange& range) {
@ -115,8 +117,11 @@ std::string FileName(CXFile file) {
// clang_getFileName return values may contain ..
ret = NormalizePath(ToString(clang_getFileName(file)));
// Resolve /usr/include/c++/7.3.0 symlink.
if (!StartsWith(ret, g_config->projectRoot))
ret = fs::canonical(ret);
if (!StartsWith(ret, g_config->projectRoot)) {
SmallString<256> dest;
sys::fs::real_path(ret, dest);
ret = dest.str();
}
return ret;
}

View File

@ -1,8 +1,8 @@
#include "filesystem.hh"
using namespace llvm;
#include "utils.h"
#include <queue>
#include <utility>
static void GetFilesInFolderHelper(
@ -10,31 +10,33 @@ static void GetFilesInFolderHelper(
bool recursive,
std::string output_prefix,
const std::function<void(const std::string&)>& handler) {
std::queue<std::pair<fs::path, fs::path>> q;
q.emplace(fs::path(folder), fs::path(output_prefix));
while (!q.empty()) {
try {
for (auto it = fs::directory_iterator(q.front().first);
it != fs::directory_iterator(); ++it) {
auto path = it->path();
std::string filename = path.filename();
if (filename[0] != '.' || filename == ".ccls") {
fs::file_status status = it->symlink_status();
if (fs::is_regular_file(status))
handler(q.front().second / filename);
else if (fs::is_directory(status) || fs::is_symlink(status)) {
if (recursive) {
std::string child_dir = q.front().second / filename;
if (fs::is_directory(status))
q.push(make_pair(path, child_dir));
}
}
}
std::error_code ec;
if (recursive)
for (sys::fs::recursive_directory_iterator I(folder, ec), E; I != E && !ec;
I.increment(ec)) {
std::string path = I->path(), filename = sys::path::filename(path);
if (filename[0] != '.' || filename == ".ccls") {
SmallString<256> Path;
if (output_prefix.size()) {
sys::path::append(Path, output_prefix, path);
handler(Path.str());
} else
handler(path);
}
}
else
for (sys::fs::directory_iterator I(folder, ec), E; I != E && !ec;
I.increment(ec)) {
std::string path = I->path(), filename = sys::path::filename(path);
if (filename[0] != '.' || filename == ".ccls") {
SmallString<256> Path;
if (output_prefix.size()) {
sys::path::append(Path, output_prefix, path);
handler(Path.str());
} else
handler(path);
}
} catch (fs::filesystem_error&) {
}
q.pop();
}
}
void GetFilesInFolder(std::string folder,

View File

@ -1,11 +1,11 @@
#pragma once
#include <experimental/filesystem>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>
#include <functional>
#include <string>
namespace fs = std::experimental::filesystem;
void GetFilesInFolder(std::string folder,
bool recursive,
bool add_folder_to_path,

View File

@ -1,6 +1,5 @@
#include "cache_manager.h"
#include "diagnostics_engine.h"
#include "filesystem.hh"
#include "import_pipeline.h"
#include "include_complete.h"
#include "message_handler.h"
@ -11,6 +10,9 @@
#include "timer.h"
#include "working_files.h"
#include "filesystem.hh"
using namespace llvm;
#include <loguru.hpp>
#include <iostream>
@ -492,10 +494,10 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
config->projectRoot = project_path;
// Create two cache directories for files inside and outside of the
// project.
fs::create_directories(config->cacheDirectory +
EscapeFileName(config->projectRoot));
fs::create_directories(config->cacheDirectory + '@' +
EscapeFileName(config->projectRoot));
sys::fs::create_directories(config->cacheDirectory +
EscapeFileName(config->projectRoot));
sys::fs::create_directories(config->cacheDirectory + '@' +
EscapeFileName(config->projectRoot));
g_config = std::move(config);
Timer time;

View File

@ -35,15 +35,17 @@ using namespace llvm::opt;
#include <vector>
struct CompileCommandsEntry {
fs::path directory;
std::string directory;
std::string file;
std::string command;
std::vector<std::string> args;
fs::path ResolveIfRelative(fs::path path) const {
if (path.is_absolute())
std::string ResolveIfRelative(std::string path) const {
if (sys::path::is_absolute(path))
return path;
return directory / path;
SmallString<256> Ret;
sys::path::append(Ret, directory, path);
return Ret.str();
}
};
MAKE_REFLECT_STRUCT(CompileCommandsEntry, directory, file, command, args);
@ -56,7 +58,7 @@ struct ProjectConfig {
std::unordered_set<std::string> quote_dirs;
std::unordered_set<std::string> angle_dirs;
std::vector<std::string> extra_flags;
fs::path project_dir;
std::string project_dir;
ProjectMode mode = ProjectMode::CompileCommandsJson;
};
@ -72,7 +74,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
const CompileCommandsEntry& entry) {
Project::Entry result;
result.filename = entry.file;
const std::string base_name = fs::path(entry.file).filename();
const std::string base_name = sys::path::filename(entry.file);
// Expand %c %cpp %clang
std::vector<std::string> args;
@ -145,7 +147,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
if (!Args.hasArg(OPT_resource_dir))
args.push_back("-resource-dir=" + g_config->clang.resourceDir);
if (!Args.hasArg(OPT_working_directory))
args.push_back("-working-directory=" + entry.directory.string());
args.push_back("-working-directory=" + entry.directory);
// There could be a clang version mismatch between what the project uses and
// what ccls uses. Make sure we do not emit warnings for mismatched options.
@ -176,10 +178,11 @@ std::vector<std::string> ReadCompilerArgumentsFromFile(
std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
std::vector<Project::Entry> result;
config->mode = ProjectMode::DotCcls;
LOG_IF_S(WARNING, !fs::exists(config->project_dir / ".ccls") &&
config->extra_flags.empty())
<< "ccls has no clang arguments. Considering adding either a "
"compile_commands.json or .ccls file. See the ccls README for "
SmallString<256> Path;
sys::path::append(Path, config->project_dir, ".ccls");
LOG_IF_S(WARNING, !sys::fs::exists(Path) && config->extra_flags.empty())
<< "ccls has no clang arguments. Use either "
"compile_commands.json or .ccls, See ccls README for "
"more information.";
std::unordered_map<std::string, std::vector<std::string>> folder_args;
@ -190,21 +193,20 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig* config) {
[&folder_args, &files](const std::string& path) {
if (SourceFileLanguage(path) != LanguageId::Unknown) {
files.push_back(path);
} else if (fs::path(path).filename() == ".ccls") {
} else if (sys::path::filename(path) == ".ccls") {
LOG_S(INFO) << "Using .ccls arguments from " << path;
folder_args.emplace(
fs::path(path).parent_path().string(),
ReadCompilerArgumentsFromFile(path));
folder_args.emplace(sys::path::parent_path(path),
ReadCompilerArgumentsFromFile(path));
}
});
const std::string project_dir = config->project_dir.string();
const std::string& project_dir = config->project_dir;
const auto& project_dir_args = folder_args[project_dir];
LOG_IF_S(INFO, !project_dir_args.empty())
<< "Using .ccls arguments " << StringJoin(project_dir_args);
auto GetCompilerArgumentForFile = [&project_dir, &folder_args](fs::path cur) {
while (!(cur = cur.parent_path()).empty()) {
auto GetCompilerArgumentForFile = [&project_dir, &folder_args](std::string cur) {
while (!(cur = sys::path::parent_path(cur)).empty()) {
auto it = folder_args.find(cur);
if (it != folder_args.end())
return it->second;
@ -235,16 +237,20 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
ProjectConfig* project,
const std::string& opt_compilation_db_dir) {
// If there is a .ccls file always load using directory listing.
if (fs::exists(project->project_dir / ".ccls"))
SmallString<256> Path;
sys::path::append(Path, project->project_dir, ".ccls");
if (sys::fs::exists(Path))
return LoadFromDirectoryListing(project);
// If |compilationDatabaseCommand| is specified, execute it to get the compdb.
fs::path comp_db_dir;
std::string comp_db_dir;
Path.clear();
if (g_config->compilationDatabaseCommand.empty()) {
project->mode = ProjectMode::CompileCommandsJson;
// Try to load compile_commands.json, but fallback to a project listing.
comp_db_dir = opt_compilation_db_dir.empty() ? project->project_dir.string()
comp_db_dir = opt_compilation_db_dir.empty() ? project->project_dir
: opt_compilation_db_dir;
sys::path::append(Path, comp_db_dir, "compile_commands.json");
} else {
project->mode = ProjectMode::ExternalCommand;
#ifdef _WIN32
@ -254,6 +260,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
if (!mkdtemp(tmpdir))
return {};
comp_db_dir = tmpdir;
sys::path::append(Path, comp_db_dir, "compile_commands.json");
rapidjson::StringBuffer input;
rapidjson::Writer<rapidjson::StringBuffer> writer(input);
JsonWriter json_writer(&writer);
@ -262,14 +269,12 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
std::vector<std::string>{g_config->compilationDatabaseCommand,
project->project_dir},
input.GetString());
FILE* fout = fopen((comp_db_dir / "compile_commands.json").c_str(), "wb");
FILE* fout = fopen(Path.c_str(), "wb");
fwrite(contents.c_str(), contents.size(), 1, fout);
fclose(fout);
#endif
}
fs::path comp_db_path = comp_db_dir / "compile_commands.json";
LOG_S(INFO) << "Trying to load " << comp_db_path.string();
CXCompilationDatabase_Error cx_db_load_error;
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(
comp_db_dir.c_str(), &cx_db_load_error);
@ -277,17 +282,18 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
#ifdef _WIN32
// TODO
#else
unlink(comp_db_path.c_str());
unlink(Path.c_str());
rmdir(comp_db_dir.c_str());
#endif
}
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
LOG_S(INFO) << "Unable to load " << comp_db_path.string()
LOG_S(INFO) << "unable to load " << Path.c_str()
<< "; using directory listing instead.";
return LoadFromDirectoryListing(project);
}
LOG_S(INFO) << "loaded " << Path.c_str();
Timer clang_time;
Timer our_time;
clang_time.Pause();
@ -437,13 +443,12 @@ Project::Entry Project::FindCompilationEntryForFile(
// |best_entry| probably has its own path in the arguments. We need to remap
// that path to the new filename.
fs::path best_entry_base_name = fs::path(best_entry->filename).filename();
std::string best_entry_base_name = sys::path::filename(best_entry->filename);
for (std::string& arg : result.args) {
try {
if (arg == best_entry->filename ||
fs::path(arg).filename() == best_entry_base_name) {
sys::path::filename(arg) == best_entry_base_name)
arg = filename;
}
} catch (...) {
}
}

View File

@ -154,7 +154,7 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
// Returns true if an element with the same file is found.
template <typename Q>
bool TryReplaceDef(std::forward_list<Q>& def_list, Q&& def) {
bool TryReplaceDef(llvm::SmallVectorImpl<Q>& def_list, Q&& def) {
for (auto& def1 : def_list)
if (def1.spell->file_id == def.spell->file_id) {
def1 = std::move(def);
@ -262,18 +262,22 @@ void QueryDatabase::RemoveUsrs(
case SymbolKind::Func: {
for (auto usr : to_remove) {
QueryFunc& func = Func(usr);
func.def.remove_if([=](const QueryFunc::Def& def) {
auto it = llvm::find_if(func.def, [=](const QueryFunc::Def& def) {
return def.spell->file_id == file_id;
});
if (it != func.def.end())
func.def.erase(it);
}
break;
}
case SymbolKind::Var: {
for (auto usr : to_remove) {
QueryVar& var = Var(usr);
var.def.remove_if([=](const QueryVar::Def& def) {
auto it = llvm::find_if(var.def, [=](const QueryVar::Def& def) {
return def.spell->file_id == file_id;
});
if (it != var.def.end())
var.def.erase(it);
}
break;
}
@ -348,7 +352,7 @@ void QueryDatabase::Update(int file_id,
QueryFunc& existing = Func(u.first);
existing.usr = u.first;
if (!TryReplaceDef(existing.def, std::move(def))) {
existing.def.push_front(std::move(def));
existing.def.push_back(std::move(def));
UpdateSymbols(&existing.symbol_idx, SymbolKind::Func, u.first);
}
}
@ -364,7 +368,7 @@ void QueryDatabase::Update(int file_id,
QueryType& existing = Type(u.first);
existing.usr = u.first;
if (!TryReplaceDef(existing.def, std::move(def))) {
existing.def.push_front(std::move(def));
existing.def.push_back(std::move(def));
UpdateSymbols(&existing.symbol_idx, SymbolKind::Type, u.first);
}
}
@ -380,7 +384,7 @@ void QueryDatabase::Update(int file_id,
QueryVar& existing = Var(u.first);
existing.usr = u.first;
if (!TryReplaceDef(existing.def, std::move(def))) {
existing.def.push_front(std::move(def));
existing.def.push_back(std::move(def));
if (!existing.def.front().is_local())
UpdateSymbols(&existing.symbol_idx, SymbolKind::Var, u.first);
}

View File

@ -3,9 +3,8 @@
#include "indexer.h"
#include "serializer.h"
#include <sparsepp/spp.h>
#include <forward_list>
#include <llvm/ADT/DenseMap.h>
#include <llvm/ADT/SmallVector.h>
struct QueryFile;
struct QueryType;
@ -69,7 +68,7 @@ using UsrUpdate =
struct QueryFunc : QueryEntity<QueryFunc, FuncDef> {
Usr usr;
int symbol_idx = -1;
std::forward_list<Def> def;
llvm::SmallVector<Def, 1> def;
std::vector<Use> declarations;
std::vector<Use> uses;
std::vector<Usr> derived;
@ -78,7 +77,7 @@ struct QueryFunc : QueryEntity<QueryFunc, FuncDef> {
struct QueryType : QueryEntity<QueryType, TypeDef> {
Usr usr;
int symbol_idx = -1;
std::forward_list<Def> def;
llvm::SmallVector<Def, 1> def;
std::vector<Use> declarations;
std::vector<Use> uses;
std::vector<Usr> derived;
@ -88,7 +87,7 @@ struct QueryType : QueryEntity<QueryType, TypeDef> {
struct QueryVar : QueryEntity<QueryVar, VarDef> {
Usr usr;
int symbol_idx = -1;
std::forward_list<Def> def;
llvm::SmallVector<Def, 1> def;
std::vector<Use> declarations;
std::vector<Use> uses;
};
@ -138,9 +137,9 @@ struct QueryDatabase {
std::vector<QueryFile> files;
std::unordered_map<std::string, int> name2file_id;
spp::sparse_hash_map<Usr, QueryFunc> usr2func;
spp::sparse_hash_map<Usr, QueryType> usr2type;
spp::sparse_hash_map<Usr, QueryVar> usr2var;
llvm::DenseMap<Usr, QueryFunc> usr2func;
llvm::DenseMap<Usr, QueryType> usr2type;
llvm::DenseMap<Usr, QueryVar> usr2var;
// Marks the given Usrs as invalid.
void RemoveUsrs(SymbolKind usr_kind, const std::vector<Usr>& to_remove);

View File

@ -11,7 +11,7 @@ Maybe<Use> GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym);
// Get defining declaration (if exists) or an arbitrary declaration (otherwise)
// for each id.
template <typename Q>
std::vector<Use> GetDeclarations(spp::sparse_hash_map<Usr, Q>& usr2entity,
std::vector<Use> GetDeclarations(llvm::DenseMap<Usr, Q>& usr2entity,
const std::vector<Usr>& usrs) {
std::vector<Use> ret;
ret.reserve(usrs.size());
@ -135,7 +135,7 @@ void EachOccurrenceWithParent(QueryDatabase* db,
}
template <typename Q, typename Fn>
void EachDefinedEntity(spp::sparse_hash_map<Usr, Q>& collection,
void EachDefinedEntity(llvm::DenseMap<Usr, Q>& collection,
const std::vector<Usr>& usrs,
Fn&& fn) {
for (Usr usr : usrs) {

View File

@ -160,7 +160,7 @@ void Reflect(Writer& visitor, IndexInclude& value) {
REFLECT_MEMBER_START();
REFLECT_MEMBER(line);
if (gTestOutputMode) {
std::string basename = fs::path(value.resolved_path).filename();
std::string basename = llvm::sys::path::filename(value.resolved_path);
if (!StartsWith(value.resolved_path, "&"))
basename = "&" + basename;
REFLECT_MEMBER2("resolved_path", basename);

View File

@ -1,6 +1,7 @@
#include "utils.h"
#include "filesystem.hh"
using namespace llvm;
#include "platform.h"
#include <doctest/doctest.h>
@ -137,12 +138,10 @@ void WriteToFile(const std::string& filename, const std::string& content) {
}
std::optional<int64_t> LastWriteTime(const std::string& filename) {
std::error_code ec;
auto ftime = fs::last_write_time(filename, ec);
if (ec) return std::nullopt;
return std::chrono::time_point_cast<std::chrono::nanoseconds>(ftime)
.time_since_epoch()
.count();
sys::fs::file_status Status;
if (sys::fs::status(filename, Status))
return {};
return Status.getLastModificationTime().time_since_epoch().count();
}
std::string GetDefaultResourceDirectory() {

@ -1 +0,0 @@
Subproject commit 1ca7189fe81ee8c59bf08196852f70843a68a63a