diff --git a/src/indexer.cc b/src/indexer.cc index f4e9be8b..443e0c8e 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -37,6 +37,7 @@ limitations under the License. #include using namespace clang; +using namespace ccls::log; namespace ccls { namespace { @@ -525,8 +526,9 @@ public: } auto i = name.find(short_name); if (short_name.size()) - while (i != std::string::npos && ((i && isIdentifierBody(name[i - 1])) || - isIdentifierBody(name[i + short_name.size()]))) + 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) { // e.g. operator type-parameter-1 @@ -751,8 +753,8 @@ public: switch (D->getKind()) { case Decl::CXXConversion: // *operator* int => *operator int* case Decl::CXXDestructor: // *~*A => *~A* - case Decl::CXXMethod: // *operator*= => *operator=* - case Decl::Function: // operator delete + case Decl::CXXMethod: // *operator*= => *operator=* + case Decl::Function: // operator delete if (Loc.isFileID()) { SourceRange R = cast(OrigD)->getNameInfo().getSourceRange(); @@ -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(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(); - llvm::IntrusiveRefCntPtr FS = llvm::vfs::getRealFileSystem(); + llvm::IntrusiveRefCntPtr FS = + llvm::vfs::getRealFileSystem(); std::shared_ptr 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) diff --git a/src/log.cc b/src/log.cc index 3e2b5592..ea909410 100644 --- a/src/log.cc +++ b/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 diff --git a/src/log.hh b/src/log.hh index 5d06d41a..46ae6582 100644 --- a/src/log.hh +++ b/src/log.hh @@ -1,41 +1,45 @@ #pragma once -#include #include +#include +#include +#include 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 > +constexpr auto operator+(T e) noexcept + -> std::enable_if_t, UT> { + return static_cast(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 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 diff --git a/src/lsp.cc b/src/lsp.cc index 5c56f324..738f278a 100644 --- a/src/lsp.cc +++ b/src/lsp.cc @@ -21,6 +21,7 @@ limitations under the License. #include #include +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; diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index c0344a34..977b0406 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -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 @@ -29,12 +29,13 @@ limitations under the License. #include #include -#include #include +#include #include namespace ccls { using namespace llvm; +using namespace ccls::log; extern std::vector 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 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 (real.empty()) - LOG_S(INFO) << "workspace folder: " << folder; - else - LOG_S(INFO) << "workspace folder: " << folder << " -> " << real; - + if (auto v = Verbosity::INFO; LogRequire(v)) { + if (real.empty()) + Log(v, "workspace folder: ", folder); + else + 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{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); diff --git a/src/messages/textDocument_completion.cc b/src/messages/textDocument_completion.cc index cf60847a..19f3960b 100644 --- a/src/messages/textDocument_completion.cc +++ b/src/messages/textDocument_completion.cc @@ -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 *items, - char quote) { + std::vector *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; diff --git a/src/messages/workspace.cc b/src/messages/workspace.cc index 60ff01ae..785ddaa0 100644 --- a/src/messages/workspace.cc +++ b/src/messages/workspace.cc @@ -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 #include @@ -30,6 +30,7 @@ limitations under the License. #include #include 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) diff --git a/src/pipeline.cc b/src/pipeline.cc index f2b75524..5a5d6611 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -41,6 +41,7 @@ limitations under the License. #include #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 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; } @@ -264,21 +268,23 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles, std::unique_lock lock(GetFileMutex(path_to_index)); prev = RawCacheLoad(path_to_index); if (!prev || CacheInvalid(vfs, prev.get(), path_to_index, entry.args, - std::nullopt)) + std::nullopt)) break; if (track) for (const auto &dep : prev->dependencies) { 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,11 +295,12 @@ 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), - request.mode != IndexMode::NonInteractive); + request.mode != IndexMode::NonInteractive); { std::lock_guard lock1(vfs->mutex); vfs->state[path_to_index].loaded++; @@ -318,7 +325,7 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles, } IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get()); on_indexed->PushBack(std::move(update), - request.mode != IndexMode::NonInteractive); + request.mode != IndexMode::NonInteractive); if (entry.id >= 0) { std::lock_guard lock2(project->mtx); project->root2folder[entry.root].path2entry_index[path] = entry.id; @@ -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> indexes; @@ -367,13 +375,13 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles, for (std::unique_ptr &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; @@ -384,7 +392,7 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles, if (retain > 0 && retain <= loaded + 1) { std::lock_guard lock(g_index_mutex); auto it = g_index.insert_or_assign( - path, InMemoryIndexFile{curr->file_contents, *curr}); + path, InMemoryIndexFile{curr->file_contents, *curr}); std::string().swap(it.first->second.index.file_contents); } if (g_config->cache.directory.size()) { @@ -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 (id.Valid()) - LOG_V(2) << "receive RequestMessage: " << id.value << " " << method; - else - LOG_V(2) << "receive NotificationMessage " << method; + if (auto v = Verbosity::VERBOSE; LogRequire(v)) { + if (id.Valid()) + Log(v, "receive RequestMessage: ", id.value, " ", method); + else + 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,9 +715,9 @@ void Standalone(const std::string &root) { Project project; WorkingFiles wfiles; VFS vfs; - SemaManager manager( - nullptr, nullptr, [&](std::string, std::vector) {}, - [](RequestId id) {}); + SemaManager manager(nullptr, nullptr, + [&](std::string, std::vector) {}, + [](RequestId id) {}); IncludeComplete complete(&project); MessageHandler handler; @@ -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()); } diff --git a/src/project.cc b/src/project.cc index 25bfa34c..8d61a0a0 100644 --- a/src/project.cc +++ b/src/project.cc @@ -37,9 +37,9 @@ limitations under the License. #include #ifdef _WIN32 -# include +#include #else -# include +#include #endif #include @@ -49,6 +49,7 @@ limitations under the License. using namespace clang; using namespace llvm; +using namespace ccls::log; namespace ccls { std::pair lookupExtension(std::string_view filename) { @@ -91,13 +92,17 @@ struct ProjectProcessor { exclude_args.insert(arg); else if (Expected 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 @@ -172,12 +177,12 @@ struct ProjectProcessor { IgnoringDiagConsumer DiagC; IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); DiagnosticsEngine Diags( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, - &DiagC, false); + IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + &DiagC, false); driver::Driver Driver(args[0], llvm::sys::getDefaultTargetTriple(), Diags); auto TargetAndMode = - driver::ToolChain::getTargetAndModeFromProgramName(args[0]); + driver::ToolChain::getTargetAndModeFromProgramName(args[0]); if (!TargetAndMode.TargetPrefix.empty()) { const char *arr[] = {"-target", TargetAndMode.TargetPrefix.c_str()}; args.insert(args.begin() + 1, std::begin(arr), std::end(arr)); @@ -193,7 +198,7 @@ struct ProjectProcessor { auto CI = std::make_unique(); CompilerInvocation::CreateFromArgs(*CI, CCArgs.data(), - CCArgs.data() + CCArgs.size(), Diags); + CCArgs.data() + CCArgs.size(), Diags); CI->getFrontendOpts().DisableFree = false; CI->getCodeGenOpts().DisableFree = false; @@ -265,25 +270,26 @@ void LoadDirectoryListing(ProjectProcessor &proc, const std::string &root, return folder.dot_ccls[root]; }; - GetFilesInFolder(root, true /*recursive*/, true /*add_folder_to_path*/, - [&folder, &files, &Seen](const std::string &path) { - std::pair lang = lookupExtension(path); - if (lang.first != LanguageId::Unknown && !lang.second) { - if (!Seen.count(path)) - files.push_back(path); - } else if (sys::path::filename(path) == ".ccls") { - std::vector args = ReadCompilerArgumentsFromFile(path); - 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; - } - }); + GetFilesInFolder( + root, true /*recursive*/, true /*add_folder_to_path*/, + [&folder, &files, &Seen](const std::string &path) { + std::pair lang = lookupExtension(path); + if (lang.first != LanguageId::Unknown && !lang.second) { + if (!Seen.count(path)) + files.push_back(path); + } else if (sys::path::filename(path) == ".ccls") { + std::vector args = ReadCompilerArgumentsFromFile(path); + 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]; + } + if (auto v = Verbosity::INFO; LogRequire(v)) + Log(v, "use ", path, ": ", l); + } + }); // If the first line of .ccls is %compile_commands.json, append extra flags. for (auto &e : folder.entries) @@ -367,8 +373,9 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) { std::vector 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 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++; } diff --git a/src/sema_manager.cc b/src/sema_manager.cc index d78b5e06..87a4def1 100644 --- a/src/sema_manager.cc +++ b/src/sema_manager.cc @@ -30,6 +30,7 @@ limitations under the License. #include using namespace clang; using namespace llvm; +using namespace ccls::log; #include #include @@ -722,12 +723,13 @@ SemaManager::EnsureSession(const std::string &path, bool *created) { session = std::make_shared( 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(); } diff --git a/src/serializer.cc b/src/serializer.cc index 0dec4710..3fd2ca59 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -30,6 +30,7 @@ limitations under the License. #include 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(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; diff --git a/src/utils.cc b/src/utils.cc index 6ebb4a6e..f57da7f6 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -36,6 +36,7 @@ limitations under the License. #include 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 diff --git a/src/working_files.cc b/src/working_files.cc index 6ba8a963..6014e915 100644 --- a/src/working_files.cc +++ b/src/working_files.cc @@ -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 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