Skip to content
This repository has been archived by the owner on Jul 30, 2020. It is now read-only.

Commit

Permalink
Look for .cquery in any directory above the source file in the hiera…
Browse files Browse the repository at this point in the history
…rchy. (#409)

* Look for .cquery in any directory above the source file in the hierarchy.

Currently cquery only reads compiler arguments (.cquery) from project
root. Under some circumstances (e.g. remote compiling), generating a
compilation database with correct path in it is non-trivial, and
allowing per directory compile arguments usually helps.

* unused var buf
  • Loading branch information
Riatre authored and MaskRay committed Feb 3, 2018
1 parent cf43abc commit d5ce584
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 23 deletions.
1 change: 0 additions & 1 deletion src/platform_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ std::string GetWorkingDirectory() {
std::string NormalizePath(const std::string& path) {
DWORD retval = 0;
TCHAR buffer[MAX_PATH] = TEXT("");
TCHAR buf[MAX_PATH] = TEXT("");
TCHAR** lpp_part = {NULL};

retval = GetFullPathName(path.c_str(), MAX_PATH, buffer, lpp_part);
Expand Down
66 changes: 47 additions & 19 deletions src/project.cc
Original file line number Diff line number Diff line change
Expand Up @@ -270,38 +270,66 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
return result;
}

std::vector<Project::Entry> LoadFromDirectoryListing(Config* init_opts,
ProjectConfig* config) {
std::vector<Project::Entry> result;

std::vector<std::string> ReadCompilerArgumentsFromFile(
const std::string& path) {
std::vector<std::string> args;
for (std::string line :
ReadLinesWithEnding(config->project_dir + "/.cquery")) {
for (std::string line : ReadLinesWithEnding(path)) {
TrimInPlace(line);
if (line.empty() || StartsWith(line, "#"))
continue;
args.push_back(line);
}
LOG_IF_S(INFO, !args.empty())
<< "Using .cquery arguments " << StringJoin(args);
return args;
}

std::vector<Project::Entry> LoadFromDirectoryListing(Config* init_opts,
ProjectConfig* config) {
std::vector<Project::Entry> result;
LOG_IF_S(WARNING, !FileExists(config->project_dir + "/.cquery") &&
config->extra_flags.empty())
<< "cquery has no clang arguments. Considering adding either a "
"compile_commands.json or .cquery file. See the cquery README for "
"more information.";

std::vector<std::string> files = GetFilesInFolder(
config->project_dir, true /*recursive*/, true /*add_folder_to_path*/);
for (const std::string& file : files) {
if (SourceFileType(file)) {
CompileCommandsEntry e;
e.directory = config->project_dir;
e.file = file;
e.args = args;
e.args.push_back(e.file);
result.push_back(
GetCompilationEntryFromCompileCommandEntry(init_opts, config, e));
std::unordered_map<std::string, std::vector<std::string>> folder_args;
std::vector<std::string> files;

GetFilesInFolder(
config->project_dir, true /*recursive*/, true /*add_folder_to_path*/,
[&folder_args, &files](const std::string& path) {
if (SourceFileType(path)) {
files.push_back(path);
} else if (GetBaseName(path) == ".cquery") {
LOG_S(INFO) << "Using .cquery arguments from " << path;
folder_args.emplace(GetDirName(path),
ReadCompilerArgumentsFromFile(path));
}
});

const auto& project_dir_args = folder_args[config->project_dir];
LOG_IF_S(INFO, !project_dir_args.empty())
<< "Using .cquery arguments " << StringJoin(project_dir_args);

auto GetCompilerArgumentForFile = [&config,
&folder_args](const std::string& path) {
for (std::string cur = GetDirName(path);
NormalizePath(cur) != config->project_dir; cur = GetDirName(cur)) {
auto it = folder_args.find(cur);
if (it != folder_args.end()) {
return it->second;
}
}
return folder_args[config->project_dir];
};

for (const std::string& file : files) {
CompileCommandsEntry e;
e.directory = config->project_dir;
e.file = file;
e.args = GetCompilerArgumentForFile(file);
e.args.push_back(e.file);
result.push_back(
GetCompilationEntryFromCompileCommandEntry(init_opts, config, e));
}

return result;
Expand Down
13 changes: 11 additions & 2 deletions src/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ bool FindAnyPartial(const std::string& value,
});
}

std::string GetDirName(std::string path) {
if (path.size() && path.back() == '/')
path.pop_back();
size_t last_slash = path.find_last_of('/');
if (last_slash == std::string::npos) return ".";
if (last_slash == 0) return "/";
return path.substr(0, last_slash);
}

std::string GetBaseName(const std::string& path) {
size_t last_slash = path.find_last_of('/');
if (last_slash != std::string::npos && (last_slash + 1) < path.size())
Expand Down Expand Up @@ -205,14 +214,14 @@ static void GetFilesInFolderHelper(
goto bail;
}

// Skip all dot files.
// Skip all dot files except .cquery.
//
// The nested ifs are intentional, branching order is subtle here.
//
// Note that in the future if we do support dot directories/files, we must
// always ignore the '.' and '..' directories otherwise this will loop
// infinitely.
if (file.name[0] != '.') {
if (file.name[0] != '.' || strcmp(file.name, ".cquery") == 0) {
if (file.is_dir) {
if (recursive) {
std::string child_dir = q.front().second + file.name + "/";
Expand Down
3 changes: 2 additions & 1 deletion src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ bool EndsWithAny(const std::string& value,
const std::vector<std::string>& endings);
bool FindAnyPartial(const std::string& value,
const std::vector<std::string>& values);

// Returns the dirname of |path|, i.e. "foo/bar.cc" => "foo", "foo" => ".", "/foo" => "/".
std::string GetDirName(std::string path);
// Returns the basename of |path|, ie, "foo/bar.cc" => "bar.cc".
std::string GetBaseName(const std::string& path);
// Returns |path| without the filetype, ie, "foo/bar.cc" => "foo/bar".
Expand Down

0 comments on commit d5ce584

Please sign in to comment.