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

Commit

Permalink
Add logging when an AbsolutePath instance is not actually absolute
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobdufault committed Apr 19, 2018
1 parent 2ed3437 commit af8997e
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 97 deletions.
14 changes: 8 additions & 6 deletions src/file_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
#include "platform.h"
#include "utils.h"

// static
AbsolutePath AbsolutePath::Build(const std::string& path) {
// TODO: add a debug-only check here that this is actually normalized.
return AbsolutePath(path);
}
#include <loguru.hpp>

AbsolutePath::AbsolutePath() {}

AbsolutePath::AbsolutePath(const std::string& path) : path(path) {}
AbsolutePath::AbsolutePath(const std::string& path, bool validate)
: path(path) {
if (validate && !IsAbsolutePath(path)) {
loguru::Text stack = loguru::stacktrace();
LOG_S(ERROR) << "Expected " << path << " to be absolute\n" << stack.c_str();
}
}

AbsolutePath::operator std::string() const {
return path;
Expand Down
10 changes: 5 additions & 5 deletions src/file_types.h
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
#pragma once

#include "hash_utils.h"
#include "serializer.h"

#include <string>

struct AbsolutePath {
// Use platform.h NormalizePath instead of calling this.
static AbsolutePath Build(const std::string& path);

// Try not to use this.
AbsolutePath();

// Provide implicit conversions to std::string for the time being.
AbsolutePath(const std::string& path);
AbsolutePath(const std::string& path, bool validate = true);
operator std::string() const;

bool operator==(const AbsolutePath& rhs) const;
bool operator!=(const AbsolutePath& rhs) const;

std::string path;
};
MAKE_HASHABLE(AbsolutePath, t.path);

void Reflect(Reader& visitor, AbsolutePath& value);
void Reflect(Writer& visitor, AbsolutePath& value);
Expand All @@ -31,4 +30,5 @@ struct Directory {
bool operator!=(const Directory& rhs) const;

std::string path;
};
};
MAKE_HASHABLE(Directory, t.path);
43 changes: 43 additions & 0 deletions src/hash_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include <functional>

// http://stackoverflow.com/a/38140932
//
// struct SomeHashKey {
// std::string key1;
// std::string key2;
// bool key3;
// };
// MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3)

inline void hash_combine(std::size_t& seed) {}

template <typename T, typename... Rest>
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
hash_combine(seed, rest...);
}

#define MAKE_HASHABLE(type, ...) \
namespace std { \
template <> \
struct hash<type> { \
std::size_t operator()(const type& t) const { \
std::size_t ret = 0; \
hash_combine(ret, __VA_ARGS__); \
return ret; \
} \
}; \
}

#define MAKE_ENUM_HASHABLE(type) \
namespace std { \
template <> \
struct hash<type> { \
std::size_t operator()(const type& t) const { \
return hash<int>()(static_cast<int>(t)); \
} \
}; \
}
6 changes: 3 additions & 3 deletions src/import_pipeline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -829,16 +829,16 @@ TEST_SUITE("ImportPipeline") {
std::unique_ptr<IndexFile> opt_previous_index;
if (!old_args.empty()) {
opt_previous_index =
std::make_unique<IndexFile>(AbsolutePath("---.cc"), "<empty>");
std::make_unique<IndexFile>(AbsolutePath("---.cc", false /*validate*/), "<empty>");
opt_previous_index->args = old_args;
}
optional<AbsolutePath> from;
if (is_dependency)
from = AbsolutePath("---.cc");
from = AbsolutePath("---.cc", false /*validate*/);
return FileNeedsParse(
is_interactive /*is_interactive*/, &timestamp_manager,
&modification_timestamp_fetcher, &import_manager, cache_manager,
opt_previous_index.get(), AbsolutePath(file), new_args, from);
opt_previous_index.get(), AbsolutePath(file, false /*validate*/), new_args, from);
};

// A file with no timestamp is not imported, since this implies the file no
Expand Down
2 changes: 1 addition & 1 deletion src/platform_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ optional<AbsolutePath> RealPathNotExpandSymlink(std::string path,
// Remove trailing slash except when a single "/".
if (resolved.size() > 1 && resolved.back() == '/')
resolved.pop_back();
return AbsolutePath(resolved);
return AbsolutePath(resolved, true /*validate*/);
}

} // namespace
Expand Down
2 changes: 1 addition & 1 deletion src/platform_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ optional<AbsolutePath> NormalizePath(const std::string& path0,
// cquery assumes forward-slashes.
std::replace(path.begin(), path.end(), '\\', '/');

return AbsolutePath(path);
return AbsolutePath(path, false /*validate*/);
}

bool TryMakeDirectory(const AbsolutePath& absolute_path) {
Expand Down
44 changes: 6 additions & 38 deletions src/project.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,6 @@ struct NormalizationCache {
}
};

bool IsUnixAbsolutePath(const std::string& path) {
return !path.empty() && path[0] == '/';
}

bool IsWindowsAbsolutePath(const std::string& path) {
auto is_drive_letter = [](char c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
};

return path.size() > 3 && path[1] == ':' &&
(path[2] == '/' || path[2] == '\\') && is_drive_letter(path[0]);
}

enum class ProjectMode { CompileCommandsJson, DotCquery, ExternalCommand };

struct ProjectConfig {
Expand Down Expand Up @@ -154,8 +141,7 @@ const std::vector<std::string>& GetSystemIncludes(

std::vector<std::string> compiler_drivers = {
GetExecutablePathNextToCqueryBinary("cquery-clang"), "clang++", "g++"};
if (IsUnixAbsolutePath(compiler_driver) ||
IsWindowsAbsolutePath(compiler_driver)) {
if (IsAbsolutePath(compiler_driver)) {
compiler_drivers.insert(compiler_drivers.begin(), compiler_driver);
}

Expand Down Expand Up @@ -229,8 +215,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
// TODO/FIXME: Normalization will fail for paths that do not exist. Should
// it return an optional<std::string>?
assert(!path.empty());
if (entry.directory.empty() || IsUnixAbsolutePath(path) ||
IsWindowsAbsolutePath(path)) {
if (entry.directory.empty() || IsAbsolutePath(path)) {
// We still want to normalize, as the path may contain .. characters.
return config->normalization_cache.Get(path);
}
Expand Down Expand Up @@ -538,7 +523,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(

comp_db_dir = opt_compilation_db_dir;

if (!IsUnixAbsolutePath(comp_db_dir) && !IsWindowsAbsolutePath(comp_db_dir)) {
if (!IsAbsolutePath(comp_db_dir)) {
comp_db_dir =
project->normalization_cache.Get(project->project_dir + comp_db_dir);
}
Expand Down Expand Up @@ -609,11 +594,11 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
our_time.Resume();
entry.directory = directory;
std::string absolute_filename;
if (IsUnixAbsolutePath(relative_filename) ||
IsWindowsAbsolutePath(relative_filename))
if (IsAbsolutePath(relative_filename)) {
absolute_filename = relative_filename;
else
} else {
absolute_filename = directory + "/" + relative_filename;
}
entry.file = project->normalization_cache.Get(absolute_filename);

result.push_back(
Expand Down Expand Up @@ -1684,23 +1669,6 @@ TEST_SUITE("Project") {
}
}

TEST_CASE("IsWindowsAbsolutePath works correctly") {
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects/"));
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
REQUIRE(IsWindowsAbsolutePath("C:\\Users\\projects"));
REQUIRE(IsWindowsAbsolutePath("C:\\\\Users\\\\projects"));
REQUIRE(IsWindowsAbsolutePath("c:\\\\Users\\\\projects"));
REQUIRE(IsWindowsAbsolutePath("A:\\\\Users\\\\projects"));

REQUIRE(!IsWindowsAbsolutePath("C:/"));
REQUIRE(!IsWindowsAbsolutePath("../abc/test"));
REQUIRE(!IsWindowsAbsolutePath("5:/test"));
REQUIRE(!IsWindowsAbsolutePath("cquery/project/file.cc"));
REQUIRE(!IsWindowsAbsolutePath(""));
REQUIRE(!IsWindowsAbsolutePath("/etc/linux/path"));
}

TEST_CASE("Entry inference prefers same file endings") {
Project p;
{
Expand Down
36 changes: 36 additions & 0 deletions src/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,42 @@ AbsolutePath GetExecutablePathNextToCqueryBinary(const std::string& name) {
return AbsolutePath(executable_path.substr(0, pos + 1) + name);
}

bool IsAbsolutePath(const std::string& path) {
return IsUnixAbsolutePath(path) || IsWindowsAbsolutePath(path);
}

bool IsUnixAbsolutePath(const std::string& path) {
return !path.empty() && path[0] == '/';
}

bool IsWindowsAbsolutePath(const std::string& path) {
auto is_drive_letter = [](char c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
};

return path.size() > 3 && path[1] == ':' &&
(path[2] == '/' || path[2] == '\\') && is_drive_letter(path[0]);
}

TEST_SUITE("AbsolutePath") {
TEST_CASE("IsWindowsAbsolutePath works correctly") {
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects/"));
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
REQUIRE(IsWindowsAbsolutePath("C:\\Users\\projects"));
REQUIRE(IsWindowsAbsolutePath("C:\\\\Users\\\\projects"));
REQUIRE(IsWindowsAbsolutePath("c:\\\\Users\\\\projects"));
REQUIRE(IsWindowsAbsolutePath("A:\\\\Users\\\\projects"));

REQUIRE(!IsWindowsAbsolutePath("C:/"));
REQUIRE(!IsWindowsAbsolutePath("../abc/test"));
REQUIRE(!IsWindowsAbsolutePath("5:/test"));
REQUIRE(!IsWindowsAbsolutePath("cquery/project/file.cc"));
REQUIRE(!IsWindowsAbsolutePath(""));
REQUIRE(!IsWindowsAbsolutePath("/etc/linux/path"));
}
}

TEST_SUITE("GetDirName") {
TEST_CASE("all") {
REQUIRE(GetDirName("") == "./");
Expand Down
47 changes: 4 additions & 43 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,46 +125,6 @@ void AddRange(std::vector<T>* dest, std::vector<T>&& to_add) {
std::make_move_iterator(to_add.end()));
}

// http://stackoverflow.com/a/38140932
//
// struct SomeHashKey {
// std::string key1;
// std::string key2;
// bool key3;
// };
// MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3)

inline void hash_combine(std::size_t& seed) {}

template <typename T, typename... Rest>
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
hash_combine(seed, rest...);
}

#define MAKE_HASHABLE(type, ...) \
namespace std { \
template <> \
struct hash<type> { \
std::size_t operator()(const type& t) const { \
std::size_t ret = 0; \
hash_combine(ret, __VA_ARGS__); \
return ret; \
} \
}; \
}

#define MAKE_ENUM_HASHABLE(type) \
namespace std { \
template <> \
struct hash<type> { \
std::size_t operator()(const type& t) const { \
return hash<int>()(static_cast<int>(t)); \
} \
}; \
}

float GetProcessMemoryUsedInMb();

std::string FormatMicroseconds(long long microseconds);
Expand All @@ -177,6 +137,7 @@ std::string UpdateToRnNewlines(std::string output);
// Get an executable located next to the cquery binary.
AbsolutePath GetExecutablePathNextToCqueryBinary(const std::string& name);

// FIXME: These should go in file_types.h; move hashing into a separate header.
MAKE_HASHABLE(AbsolutePath, t.path);
MAKE_HASHABLE(Directory, t.path);
// Utility methods to check if |path| is absolute.
bool IsAbsolutePath(const std::string& path);
bool IsUnixAbsolutePath(const std::string& path);
bool IsWindowsAbsolutePath(const std::string& path);

0 comments on commit af8997e

Please sign in to comment.