improvge and fix UB of the use of log

https://github.com/MaskRay/ccls/blob/master/src/main.cc#L90 is not
relyable because `1` and `2` are out of range of `enum Verbosity`.
According to CWG 1766:

> A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (10.2 [dcl.enum]). Otherwise, the resulting value is unspecified (and might not be in that range) behavior is undefined.

so, stuff like LOG_V(1) and LOG_V(2) are UB. The solution is either:

Message(Verbosity verbosity, const char* file, int line); ->   Message(int verbosity, const char* file, int line);

or

```c++
enum Verbosity {
  Verbosity_FATAL = -3,
  Verbosity_ERROR = -2,
  Verbosity_WARNING = -1,
  Verbosity_INFO = 0,
  // more level...
};
```

IMO the latter is better option.

This pr also replace macros inside log.hh with short functions and
replace `enum Verbosity` with `enum class Verbosity`
This commit is contained in:
firstlove 2019-03-23 17:52:14 +08:00
parent b7d9ced086
commit c0ef47d5e0
13 changed files with 213 additions and 150 deletions

View File

@ -37,6 +37,7 @@ limitations under the License.
#include <unordered_set>
using namespace clang;
using namespace ccls::log;
namespace ccls {
namespace {
@ -525,7 +526,8 @@ public:
}
auto i = name.find(short_name);
if (short_name.size())
while (i != std::string::npos && ((i && isIdentifierBody(name[i - 1])) ||
while (i != std::string::npos &&
((i && isIdentifierBody(name[i - 1])) ||
isIdentifierBody(name[i + short_name.size()])))
i = name.find(short_name, i + short_name.size());
if (i == std::string::npos) {
@ -794,9 +796,9 @@ public:
switch (kind) {
case Kind::Invalid:
if (ls_kind == SymbolKind::Unknown)
LOG_S(INFO) << "Unhandled " << int(D->getKind()) << " "
<< info->qualified << " in " << db->path << ":"
<< (loc.start.line + 1) << ":" << (loc.start.column + 1);
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "Unhandled ", int(D->getKind()), " ", info->qualified, " in ",
db->path, ":", (loc.start.line + 1), ":", (loc.start.column + 1));
return true;
case Kind::File:
return true;
@ -952,12 +954,14 @@ public:
if (auto *RD = dyn_cast<RecordDecl>(D)) {
if (type->def.detailed_name[0] == '\0' && info->short_name.empty()) {
StringRef Tag;
// clang-format off
switch (RD->getTagKind()) {
case TTK_Struct: Tag = "struct"; break;
case TTK_Interface: Tag = "__interface"; break;
case TTK_Union: Tag = "union"; break;
case TTK_Class: Tag = "class"; break;
case TTK_Enum: Tag = "enum"; break;
// clang-format on
}
if (TypedefNameDecl *TD = RD->getTypedefNameForAnonDecl()) {
StringRef Name = TD->getName();
@ -1220,7 +1224,8 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
bool &ok) {
ok = true;
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(main, args, FS);
// e.g. .s
@ -1288,12 +1293,14 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
ok = true;
};
if (!CRC.RunSafely(parse)) {
LOG_S(ERROR) << "clang crashed for " << main;
if (auto v = Verbosity::ERROR; LogRequire(v))
Log(v, "clang crashed for ", main);
return {};
}
}
if (!ok) {
LOG_S(ERROR) << "failed to index " << main;
if (auto v = Verbosity::ERROR; LogRequire(v))
Log(v, "failed to index ", main);
return {};
}
for (auto &Buf : Bufs)

View File

@ -56,11 +56,13 @@ Message::Message(Verbosity verbosity, const char *file, int line)
stream_ << ' ';
// clang-format off
switch (verbosity_) {
case Verbosity_FATAL: stream_ << 'F'; break;
case Verbosity_ERROR: stream_ << 'E'; break;
case Verbosity_WARNING: stream_ << 'W'; break;
case Verbosity_INFO: stream_ << 'I'; break;
default: stream_ << "V(" << int(verbosity_) << ')';
case Verbosity::FATAL: stream_ << 'F'; break;
case Verbosity::ERROR: stream_ << 'E'; break;
case Verbosity::WARNING: stream_ << 'W'; break;
case Verbosity::INFO: stream_ << 'I'; break;
case Verbosity::DEBUG: stream_ << 'D'; break;
case Verbosity::VERBOSE: stream_ << 'V'; break;
default: stream_ << "V(" << +verbosity_ << ')';
}
// clang-format on
stream_ << ' ';
@ -73,7 +75,7 @@ Message::~Message() {
stream_ << '\n';
fputs(stream_.str().c_str(), file);
fflush(file);
if (verbosity_ == Verbosity_FATAL)
if (verbosity_ == Verbosity::FATAL)
abort();
}
} // namespace ccls::log

View File

@ -1,41 +1,45 @@
#pragma once
#include <stdio.h>
#include <sstream>
#include <stdio.h>
#include <string>
#include <type_traits>
namespace ccls::log {
extern FILE* file;
extern FILE *file;
struct Voidify {
void operator&(const std::ostream&) {}
enum class Verbosity : signed {
FATAL = -3,
ERROR = -2,
WARNING = -1,
INFO = 0,
DEBUG = 1,
VERBOSE = 2
};
template <typename T, typename UT = std::underlying_type_t<T>>
constexpr auto operator+(T e) noexcept
-> std::enable_if_t<std::is_enum_v<T>, UT> {
return static_cast<UT>(e);
}
enum Verbosity {
Verbosity_FATAL = -3,
Verbosity_ERROR = -2,
Verbosity_WARNING = -1,
Verbosity_INFO = 0,
};
extern Verbosity verbosity;
struct Message {
std::stringstream stream_;
int verbosity_;
Verbosity verbosity_;
Message(Verbosity verbosity, const char* file, int line);
Message(Verbosity verbosity, const char *file, int line);
~Message();
};
template <typename... Args> inline void Log(Verbosity v, Args const &... args) {
(Message(v, __FILE__, __LINE__).stream_ << ... << args);
}
#define LOG_IF(v, cond) \
!(cond) ? void(0) \
: ccls::log::Voidify() & \
ccls::log::Message(v, __FILE__, __LINE__).stream_
#define LOG_S(v) \
LOG_IF(ccls::log::Verbosity_##v, \
ccls::log::Verbosity_##v <= ccls::log::verbosity)
#define LOG_IF_S(v, cond) \
LOG_IF(ccls::log::Verbosity_##v, \
(cond) && ccls::log::Verbosity_##v <= ccls::log::verbosity)
#define LOG_V_ENABLED(v) (v <= ccls::log::verbosity)
#define LOG_V(v) LOG_IF(ccls::log::Verbosity(v), LOG_V_ENABLED(v))
// XXX: According to CWG 1766, static_cast invalid(out of range) value to enum
// class is UB
bool inline LogRequire(Verbosity v) { return +v <= +verbosity; }
// ADL
bool inline LogIf(Verbosity v, bool cond) { return cond && LogRequire(v); }
} // namespace ccls::log

View File

@ -21,6 +21,7 @@ limitations under the License.
#include <algorithm>
#include <stdio.h>
using namespace ccls::log;
namespace ccls {
void Reflect(JsonReader &vis, RequestId &v) {
@ -103,9 +104,9 @@ void DocumentUri::SetPath(const std::string &path) {
std::string DocumentUri::GetPath() const {
if (raw_uri.compare(0, 7, "file://")) {
LOG_S(WARNING)
<< "Received potentially bad URI (not starting with file://): "
<< raw_uri;
if (auto v = Verbosity::WARNING; LogRequire(v))
Log(v, "Received potentially bad URI (not starting with file://): ",
raw_uri);
return raw_uri;
}
std::string ret;

View File

@ -13,7 +13,6 @@ See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "sema_manager.hh"
#include "filesystem.hh"
#include "include_complete.hh"
#include "log.hh"
@ -21,6 +20,7 @@ limitations under the License.
#include "pipeline.hh"
#include "platform.hh"
#include "project.hh"
#include "sema_manager.hh"
#include "working_files.hh"
#include <llvm/ADT/Twine.h>
@ -29,12 +29,13 @@ limitations under the License.
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <stdlib.h>
#include <stdexcept>
#include <stdlib.h>
#include <thread>
namespace ccls {
using namespace llvm;
using namespace ccls::log;
extern std::vector<std::string> g_init_options;
@ -184,7 +185,8 @@ REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol,
hierarchicalDocumentSymbolSupport);
REFLECT_STRUCT(TextDocumentClientCap::LinkSupport, linkSupport);
REFLECT_STRUCT(TextDocumentClientCap::PublishDiagnostics, relatedInformation);
REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol, publishDiagnostics);
REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol,
publishDiagnostics);
struct ClientCap {
WorkspaceClientCap workspace;
@ -268,8 +270,9 @@ void *Indexer(void *arg_) {
void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
std::string project_path = NormalizePath(param.rootUri->GetPath());
LOG_S(INFO) << "initialize in directory " << project_path << " with uri "
<< param.rootUri->raw_uri;
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "initialize in directory ", project_path, " with uri ",
param.rootUri->raw_uri);
{
g_config = new Config(param.initializationOptions);
@ -291,7 +294,8 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
JsonWriter json_writer(&writer);
Reflect(json_writer, *g_config);
LOG_S(INFO) << "initializationOptions: " << output.GetString();
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "initializationOptions: ", output.GetString());
if (g_config->cache.directory.size()) {
SmallString<256> Path(g_config->cache.directory);
@ -320,7 +324,8 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
if (g_config->clang.resourceDir.empty())
g_config->clang.resourceDir = GetDefaultResourceDirectory();
DoPathMapping(g_config->clang.resourceDir);
LOG_S(INFO) << "use -resource-dir=" << g_config->clang.resourceDir;
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "use -resource-dir=", g_config->clang.resourceDir);
// Send initialization before starting indexers, so we don't send a
// status update too early.
@ -352,11 +357,12 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
std::sort(workspaceFolders.begin(), workspaceFolders.end(),
[](auto &l, auto &r) { return l.first.size() > r.first.size(); });
for (auto &[folder, real] : workspaceFolders)
if (auto v = Verbosity::INFO; LogRequire(v)) {
if (real.empty())
LOG_S(INFO) << "workspace folder: " << folder;
Log(v, "workspace folder: ", folder);
else
LOG_S(INFO) << "workspace folder: " << folder << " -> " << real;
Log(v, "workspace folder: ", folder, " -> ", real);
}
if (g_config->cache.directory.empty())
g_config->cache.retainInMemory = 1;
else if (!g_config->cache.hierarchicalPath)
@ -378,7 +384,8 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
if (g_config->index.threads == 0)
g_config->index.threads = std::thread::hardware_concurrency();
LOG_S(INFO) << "start " << g_config->index.threads << " indexers";
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "start ", g_config->index.threads, " indexers");
for (int i = 0; i < g_config->index.threads; i++)
SpawnThread(Indexer, new std::pair<MessageHandler *, int>{m, i});
@ -386,7 +393,8 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
// files, because that takes a long time.
m->include_complete->Rescan();
LOG_S(INFO) << "dispatch initial index requests";
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "dispatch initial index requests");
m->project->Index(m->wfiles, reply.id);
m->manager->sessions.SetCapacity(g_config->session.maxNum);

View File

@ -31,6 +31,7 @@ limitations under the License.
namespace ccls {
using namespace clang;
using namespace llvm;
using namespace ccls::log;
REFLECT_UNDERLYING(InsertTextFormat);
REFLECT_UNDERLYING(CompletionItemKind);
@ -61,8 +62,7 @@ REFLECT_STRUCT(CompletionList, isIncomplete, items);
#if LLVM_VERSION_MAJOR < 8
void DecorateIncludePaths(const std::smatch &match,
std::vector<CompletionItem> *items,
char quote) {
std::vector<CompletionItem> *items, char quote) {
std::string spaces_after_include = " ";
if (match[3].compare("include") == 0 && quote != '\0')
spaces_after_include = match[4].str();
@ -161,12 +161,15 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text,
auto &edits = item.additionalTextEdits;
if (overwrite_len > 0) {
item.textEdit.range.start = overwrite_begin;
std::string orig = buffer_line.substr(overwrite_begin.character, overwrite_len);
std::string orig =
buffer_line.substr(overwrite_begin.character, overwrite_len);
if (edits.size() && edits[0].range.end == begin_pos &&
edits[0].range.start.line == begin_pos.line) {
int cur_edit_len = edits[0].range.end.character - edits[0].range.start.character;
int cur_edit_len =
edits[0].range.end.character - edits[0].range.start.character;
item.textEdit.newText =
buffer_line.substr(overwrite_begin.character, overwrite_len - cur_edit_len) +
buffer_line.substr(overwrite_begin.character,
overwrite_len - cur_edit_len) +
edits[0].newText + item.textEdit.newText;
edits.erase(edits.begin());
} else {
@ -304,7 +307,8 @@ CompletionItemKind GetCompletionKind(CodeCompletionContext::Kind K,
return CompletionItemKind::Field;
default:
LOG_S(WARNING) << "Unhandled " << int(D->getKind());
if (auto v = Verbosity::WARNING; LogRequire(v))
Log(v, "Unhandled ", int(D->getKind()));
return CompletionItemKind::Text;
}
break;

View File

@ -13,13 +13,13 @@ See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "sema_manager.hh"
#include "fuzzy_match.hh"
#include "log.hh"
#include "message_handler.hh"
#include "pipeline.hh"
#include "project.hh"
#include "query.hh"
#include "sema_manager.hh"
#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringRef.h>
@ -30,6 +30,7 @@ limitations under the License.
#include <functional>
#include <limits.h>
using namespace llvm;
using namespace ccls::log;
namespace ccls {
REFLECT_STRUCT(SymbolInformation, name, kind, location, containerName);
@ -81,7 +82,8 @@ void MessageHandler::workspace_didChangeWorkspaceFolders(
for (const WorkspaceFolder &wf : param.event.removed) {
std::string root = wf.uri.GetPath();
EnsureEndsInSlash(root);
LOG_S(INFO) << "delete workspace folder " << wf.name << ": " << root;
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "delete workspace folder ", wf.name, ": ", root);
auto it = llvm::find_if(g_config->workspaceFolders,
[&](auto &folder) { return folder.first == root; });
if (it != g_config->workspaceFolders.end()) {
@ -100,8 +102,9 @@ void MessageHandler::workspace_didChangeWorkspaceFolders(
std::string real = RealPath(folder) + '/';
if (folder == real)
real.clear();
LOG_S(INFO) << "add workspace folder " << wf.name << ": "
<< (real.empty() ? folder : folder + " -> " + real);
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "add workspace folder ", wf.name, ": ",
(real.empty() ? folder : folder + " -> " + real));
workspaceFolders.emplace_back();
auto it = workspaceFolders.end() - 1;
for (; it != workspaceFolders.begin() && folder < it[-1].first; --it)

View File

@ -41,6 +41,7 @@ limitations under the License.
#include <unistd.h>
#endif
using namespace llvm;
using namespace ccls::log;
namespace chrono = std::chrono;
namespace ccls {
@ -118,8 +119,9 @@ bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
{
std::lock_guard<std::mutex> lock(vfs->mutex);
if (prev->mtime < vfs->state[path].timestamp) {
LOG_V(1) << "timestamp changed for " << path
<< (from ? " (via " + *from + ")" : std::string());
if (auto v = Verbosity::DEBUG; LogRequire(v))
Log(v, "timestamp changed for ", path,
(from ? " (via " + *from + ")" : std::string()));
return true;
}
}
@ -131,8 +133,9 @@ bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
if (strcmp(prev->args[i], args[i]) && sys::path::stem(args[i]) != stem)
changed = true;
if (changed)
LOG_V(1) << "args changed for " << path
<< (from ? " (via " + *from + ")" : std::string());
if (auto v = Verbosity::DEBUG; LogRequire(v))
Log(v, "args changed for ", path,
(from ? " (via " + *from + ")" : std::string()));
return changed;
};
@ -215,7 +218,8 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
}
if (!matcher.Matches(request.path)) {
LOG_IF_S(INFO, loud) << "skip " << request.path;
if (auto v = Verbosity::INFO; LogIf(v, loud))
Log(v, "skip ", request.path);
return false;
}
@ -271,14 +275,16 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
if (auto mtime1 = LastWriteTime(dep.first.val().str())) {
if (dep.second < *mtime1) {
reparse = 2;
LOG_V(1) << "timestamp changed for " << path_to_index << " via "
<< dep.first.val().str();
if (auto v = Verbosity::DEBUG; LogRequire(v))
Log(v, "timestamp changed for ", path_to_index, " via ",
dep.first.val().str());
break;
}
} else {
reparse = 2;
LOG_V(1) << "timestamp changed for " << path_to_index << " via "
<< dep.first.val().str();
if (auto v = Verbosity::DEBUG; LogRequire(v))
Log(v, "timestamp changed for ", path_to_index, " via ",
dep.first.val().str());
break;
}
}
@ -289,7 +295,8 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
if (vfs->Loaded(path_to_index))
return true;
LOG_S(INFO) << "load cache for " << path_to_index;
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "load cache for ", path_to_index);
auto dependencies = prev->dependencies;
IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
on_indexed->PushBack(std::move(update),
@ -329,12 +336,13 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
if (loud) {
std::string line;
if (LOG_V_ENABLED(1)) {
if (LogRequire(Verbosity::DEBUG)) {
line = "\n ";
for (auto &arg : entry.args)
(line += ' ') += arg;
}
LOG_S(INFO) << (deleted ? "delete " : "parse ") << path_to_index << line;
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, (deleted ? "delete " : "parse "), path_to_index, line);
}
std::vector<std::unique_ptr<IndexFile>> indexes;
@ -367,13 +375,13 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
for (std::unique_ptr<IndexFile> &curr : indexes) {
std::string path = curr->path;
if (!matcher.Matches(path)) {
LOG_IF_S(INFO, loud) << "skip index for " << path;
if (auto v = Verbosity::INFO; LogIf(Verbosity::INFO, loud))
Log(v, "skip index for ", path);
continue;
}
if (!deleted)
LOG_IF_S(INFO, loud) << "store index for " << path
<< " (delta: " << !!prev << ")";
if (auto v = Verbosity::INFO; LogIf(v, loud) && !deleted)
Log(v, "store index for ", path, " (delta: ", !!prev, ")");
{
std::lock_guard lock(GetFileMutex(path));
int loaded = vfs->Loaded(path), retain = g_config->cache.retainInMemory;
@ -468,8 +476,9 @@ void Indexer_Main(SemaManager *manager, VFS *vfs, Project *project,
void Main_OnIndexed(DB *db, WorkingFiles *wfiles, IndexUpdate *update) {
if (update->refresh) {
LOG_S(INFO)
<< "loaded project. Refresh semantic highlight for all working file.";
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v,
"loaded project. Refresh semantic highlight for all working file.");
std::lock_guard lock(wfiles->mutex);
for (auto &[f, wf] : wfiles->files) {
std::string path = LowerPathIfInsensitive(f);
@ -545,10 +554,12 @@ void LaunchStdin() {
std::string method;
ReflectMember(reader, "id", id);
ReflectMember(reader, "method", method);
if (auto v = Verbosity::VERBOSE; LogRequire(v)) {
if (id.Valid())
LOG_V(2) << "receive RequestMessage: " << id.value << " " << method;
Log(v, "receive RequestMessage: ", id.value, " ", method);
else
LOG_V(2) << "receive NotificationMessage " << method;
Log(v, "receive NotificationMessage ", method);
}
if (method.empty())
continue;
received_exit = method == "exit";
@ -574,7 +585,8 @@ void LaunchStdin() {
chrono::steady_clock::now()});
}
ThreadLeave();
}).detach();
})
.detach();
}
void LaunchStdout() {
@ -592,7 +604,8 @@ void LaunchStdout() {
break;
}
ThreadLeave();
}).detach();
})
.detach();
}
void MainLoop() {
@ -702,8 +715,8 @@ void Standalone(const std::string &root) {
Project project;
WorkingFiles wfiles;
VFS vfs;
SemaManager manager(
nullptr, nullptr, [&](std::string, std::vector<Diagnostic>) {},
SemaManager manager(nullptr, nullptr,
[&](std::string, std::vector<Diagnostic>) {},
[](RequestId id) {});
IncludeComplete complete(&project);
@ -781,7 +794,8 @@ void NotifyOrRequest(const char *method, bool request,
JsonWriter writer(&w);
fn(writer);
w.EndObject();
LOG_V(2) << (request ? "RequestMessage: " : "NotificationMessage: ") << method;
if (auto v = Verbosity::VERBOSE; LogRequire(v))
Log(v, (request ? "RequestMessage: " : "NotificationMessage: "), method);
for_stdout->PushBack(output.GetString());
}
@ -809,8 +823,8 @@ static void Reply(RequestId id, const char *key,
JsonWriter writer(&w);
fn(writer);
w.EndObject();
if (id.Valid())
LOG_V(2) << "respond to RequestMessage: " << id.value;
if (auto v = Verbosity::VERBOSE; LogRequire(v) && id.Valid())
Log(v, "respond to RequestMessage: ", id.value);
for_stdout->PushBack(output.GetString());
}

View File

@ -37,9 +37,9 @@ limitations under the License.
#include <rapidjson/writer.h>
#ifdef _WIN32
# include <Windows.h>
#include <Windows.h>
#else
# include <unistd.h>
#include <unistd.h>
#endif
#include <array>
@ -49,6 +49,7 @@ limitations under the License.
using namespace clang;
using namespace llvm;
using namespace ccls::log;
namespace ccls {
std::pair<LanguageId, bool> lookupExtension(std::string_view filename) {
@ -91,13 +92,17 @@ struct ProjectProcessor {
exclude_args.insert(arg);
else if (Expected<GlobPattern> glob_or_err = GlobPattern::create(arg))
exclude_globs.push_back(std::move(*glob_or_err));
else
LOG_S(WARNING) << toString(glob_or_err.takeError());
else {
if (auto v = Verbosity::WARNING; LogRequire(v))
Log(v, toString(glob_or_err.takeError()));
}
}
bool ExcludesArg(StringRef arg) {
// clang-format off
return exclude_args.count(arg) || any_of(exclude_globs,
[&](const GlobPattern &glob) { return glob.match(arg); });
// clang-format on
}
// Expand %c %cpp ... in .ccls
@ -265,7 +270,8 @@ void LoadDirectoryListing(ProjectProcessor &proc, const std::string &root,
return folder.dot_ccls[root];
};
GetFilesInFolder(root, true /*recursive*/, true /*add_folder_to_path*/,
GetFilesInFolder(
root, true /*recursive*/, true /*add_folder_to_path*/,
[&folder, &files, &Seen](const std::string &path) {
std::pair<LanguageId, bool> lang = lookupExtension(path);
if (lang.first != LanguageId::Unknown && !lang.second) {
@ -273,15 +279,15 @@ void LoadDirectoryListing(ProjectProcessor &proc, const std::string &root,
files.push_back(path);
} else if (sys::path::filename(path) == ".ccls") {
std::vector<const char *> args = ReadCompilerArgumentsFromFile(path);
folder.dot_ccls.emplace(sys::path::parent_path(path),
args);
folder.dot_ccls.emplace(sys::path::parent_path(path), args);
std::string l;
for (size_t i = 0; i < args.size(); i++) {
if (i)
l += ' ';
l += args[i];
}
LOG_S(INFO) << "use " << path << ": " << l;
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "use ", path, ": ", l);
}
});
@ -367,8 +373,9 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
std::vector<StringRef> args{g_config->compilationDatabaseCommand, root};
if (sys::ExecuteAndWait(args[0], args, llvm::None, Redir, 0, 0, &err_msg) <
0) {
LOG_S(ERROR) << "failed to execute " << args[0].str() << " "
<< args[1].str() << ": " << err_msg;
if (auto v = Verbosity::ERROR; LogRequire(v))
Log(v, "failed to execute ", args[0].str(), " ", args[1].str(), ": ",
err_msg);
return;
}
}
@ -392,9 +399,11 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
std::vector<Project::Entry> result;
if (!CDB) {
if (g_config->compilationDatabaseCommand.size() || sys::fs::exists(Path))
LOG_S(ERROR) << "failed to load " << Path.c_str();
if (auto v = Verbosity::ERROR; LogRequire(v))
Log(v, "failed to load ", Path.c_str());
} else {
LOG_S(INFO) << "loaded " << Path.c_str();
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "loaded ", Path.c_str());
for (tooling::CompileCommand &Cmd : CDB->getAllCompileCommands()) {
static bool once;
Project::Entry entry;
@ -458,7 +467,8 @@ void Project::Load(const std::string &root) {
LoadDirectory(root, folder);
for (auto &[path, kind] : folder.search_dir2kind)
LOG_S(INFO) << "search directory: " << path << ' ' << " \"< "[kind];
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "search directory: ", path, ' ', " \"< "[kind]);
// Setup project entries.
folder.path2entry_index.reserve(folder.entries.size());
@ -579,8 +589,9 @@ void Project::Index(WorkingFiles *wfiles, RequestId id) {
: IndexMode::NonInteractive,
false, id);
} else {
LOG_V(1) << "[" << i << "/" << folder.entries.size() << "]: " << reason
<< "; skip " << entry.filename;
if (auto v = Verbosity::DEBUG; LogRequire(v))
Log(v, "[", i, "/", folder.entries.size(), "]: ", reason, "; skip ",
entry.filename);
}
i++;
}

View File

@ -30,6 +30,7 @@ limitations under the License.
#include <llvm/Support/Threading.h>
using namespace clang;
using namespace llvm;
using namespace ccls::log;
#include <algorithm>
#include <chrono>
@ -722,12 +723,13 @@ SemaManager::EnsureSession(const std::string &path, bool *created) {
session = std::make_shared<ccls::Session>(
project_->FindEntry(path, false, false), wfiles, PCH);
std::string line;
if (LOG_V_ENABLED(1)) {
if (LogRequire(Verbosity::DEBUG)) {
line = "\n ";
for (auto &arg : session->file.args)
(line += ' ') += arg;
}
LOG_S(INFO) << "create session for " << path << line;
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "create session for ", path, line);
sessions.Insert(path, session);
if (created)
*created = true;
@ -736,7 +738,8 @@ SemaManager::EnsureSession(const std::string &path, bool *created) {
}
void SemaManager::Clear() {
LOG_S(INFO) << "clear all sessions";
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "clear all sessions");
std::lock_guard lock(mutex);
sessions.Clear();
}

View File

@ -30,6 +30,7 @@ limitations under the License.
#include <stdexcept>
using namespace llvm;
using namespace ccls::log;
bool gTestOutputMode = false;
@ -426,9 +427,7 @@ CachedHashStringRef InternH(StringRef S) {
return *R.first;
}
const char *Intern(StringRef S) {
return InternH(S).val().data();
}
const char *Intern(StringRef S) { return InternH(S).val().data(); }
std::string Serialize(SerializeFormat format, IndexFile &file) {
switch (format) {
@ -485,7 +484,8 @@ Deserialize(SerializeFormat format, const std::string &path,
file = std::make_unique<IndexFile>(path, file_content);
ReflectFile(reader, *file);
} catch (std::invalid_argument &e) {
LOG_S(INFO) << "failed to deserialize '" << path << "': " << e.what();
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "failed to deserialize '", path, "': ", e.what());
return nullptr;
}
break;
@ -510,8 +510,9 @@ Deserialize(SerializeFormat format, const std::string &path,
try {
ReflectFile(json_reader, *file);
} catch (std::invalid_argument &e) {
LOG_S(INFO) << "'" << path << "': failed to deserialize "
<< json_reader.GetPath() << "." << e.what();
if (auto v = Verbosity::INFO; LogRequire(v))
Log(v, "'", path, "': failed to deserialize ", json_reader.GetPath(),
".", e.what());
return nullptr;
}
break;

View File

@ -36,6 +36,7 @@ limitations under the License.
#include <unordered_map>
using namespace llvm;
using namespace ccls::log;
namespace ccls {
struct Matcher::Impl {
@ -182,7 +183,8 @@ void WriteToFile(const std::string &filename, const std::string &content) {
FILE *f = fopen(filename.c_str(), "wb");
if (!f ||
(content.size() && fwrite(content.c_str(), content.size(), 1, f) != 1)) {
LOG_S(ERROR) << "failed to write to " << filename << ' ' << strerror(errno);
if (auto v = Verbosity::ERROR; LogRequire(v))
Log(v, "failed to write to ", filename, ' ', strerror(errno));
return;
}
fclose(f);
@ -206,4 +208,4 @@ int ReverseSubseqMatch(std::string_view pat, std::string_view text,
}
std::string GetDefaultResourceDirectory() { return DEFAULT_RESOURCE_DIRECTORY; }
}
} // namespace ccls

View File

@ -28,6 +28,7 @@ namespace chrono = std::chrono;
using namespace clang;
using namespace llvm;
using namespace ccls::log;
namespace ccls {
namespace {
@ -329,8 +330,9 @@ std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
if (line == (int)index_lines.size() && !*column)
return buffer_content.size();
if (line < 0 || line >= (int)index_lines.size()) {
LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, "
<< index_lines.size() << ")) in " << filename;
if (auto v = Verbosity::WARNING; LogRequire(v))
Log(v, "bad index_line (got ", line, ", expected [0, ",
index_lines.size(), ")) in ", filename);
return std::nullopt;
}
@ -406,7 +408,8 @@ void WorkingFiles::OnChange(const TextDocumentDidChangeParam &change) {
std::string path = change.textDocument.uri.GetPath();
WorkingFile *file = GetFileUnlocked(path);
if (!file) {
LOG_S(WARNING) << "Could not change " << path << " because it was not open";
if (auto v = Verbosity::WARNING; LogRequire(v))
Log(v,"Could not change ", path, " because it was not open");
return;
}
@ -482,4 +485,4 @@ std::string_view LexIdentifierAroundPos(Position position,
return content.substr(start, end - start);
}
}
} // namespace ccls