mirror of
https://github.com/MaskRay/ccls.git
synced 2025-06-07 16:54:54 +00:00
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:
parent
b7d9ced086
commit
c0ef47d5e0
@ -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)
|
||||
|
14
src/log.cc
14
src/log.cc
@ -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
|
||||
|
52
src/log.hh
52
src/log.hh
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user