From 5a723b489a5c7003802dca22f4a6c09b8400dddb Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 26 Nov 2018 22:22:27 -0800 Subject: [PATCH] Refactor Matcher to use pimpl and merge match.hh into utils.hh --- CMakeLists.txt | 1 - src/clang_complete.cc | 3 +- src/include_complete.cc | 7 ++-- src/indexer.cc | 3 +- src/match.cc | 77 ------------------------------------- src/match.hh | 45 ---------------------- src/message_handler.cc | 3 +- src/messages/ccls_reload.cc | 1 - src/pipeline.cc | 5 +-- src/project.cc | 5 +-- src/utils.cc | 59 ++++++++++++++++++++++++++++ src/utils.hh | 21 ++++++++++ 12 files changed, 90 insertions(+), 140 deletions(-) delete mode 100644 src/match.cc delete mode 100644 src/match.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d608c90..b794d398 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,7 +190,6 @@ target_sources(ccls PRIVATE src/indexer.cc src/log.cc src/lsp.cc - src/match.cc src/message_handler.cc src/pipeline.cc src/platform_posix.cc diff --git a/src/clang_complete.cc b/src/clang_complete.cc index f4fde92c..3132a523 100644 --- a/src/clang_complete.cc +++ b/src/clang_complete.cc @@ -18,7 +18,6 @@ limitations under the License. #include "clang_tu.hh" #include "filesystem.hh" #include "log.hh" -#include "match.hh" #include "platform.hh" #include @@ -585,7 +584,7 @@ void CompletionManager::DiagnosticsUpdate(const std::string &path, int debounce) { static GroupMatch match(g_config->diagnostics.whitelist, g_config->diagnostics.blacklist); - if (!match.IsMatch(path)) + if (!match.Matches(path)) return; int64_t now = chrono::duration_cast( chrono::high_resolution_clock::now().time_since_epoch()) diff --git a/src/include_complete.cc b/src/include_complete.cc index 7f293336..b7834d61 100644 --- a/src/include_complete.cc +++ b/src/include_complete.cc @@ -16,7 +16,6 @@ limitations under the License. #include "include_complete.hh" #include "filesystem.hh" -#include "match.hh" #include "platform.hh" #include "project.hh" @@ -162,7 +161,7 @@ void IncludeComplete::AddFile(const std::string &path) { ok = true; if (!ok) return; - if (match_ && !match_->IsMatch(path)) + if (match_ && !match_->Matches(path)) return; std::string trimmed_path = path; @@ -179,7 +178,7 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory, bool use_angle_brackets) { directory = NormalizePath(directory); EnsureEndsInSlash(directory); - if (match_ && !match_->IsMatch(directory)) + if (match_ && !match_->Matches(directory)) return; bool include_cpp = directory.find("include/c++") != std::string::npos; @@ -193,7 +192,7 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory, ok = true; if (!ok) return; - if (match_ && !match_->IsMatch(directory + path)) + if (match_ && !match_->Matches(directory + path)) return; CompletionCandidate candidate; diff --git a/src/indexer.cc b/src/indexer.cc index db0d56eb..b833589f 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -18,7 +18,6 @@ limitations under the License. #include "clang_complete.hh" #include "clang_tu.hh" #include "log.hh" -#include "match.hh" #include "pipeline.hh" #include "platform.hh" #include "serializer.hh" @@ -97,7 +96,7 @@ struct IndexParam { bool UseMultiVersion(const FileEntry &FE) { auto it = UID2multi.try_emplace(FE.getUniqueID()); if (it.second) - it.first->second = multiVersionMatcher->IsMatch(PathFromFileEntry(FE)); + it.first->second = multiVersionMatcher->Matches(PathFromFileEntry(FE)); return it.first->second; } }; diff --git a/src/match.cc b/src/match.cc deleted file mode 100644 index dc851551..00000000 --- a/src/match.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright 2017-2018 ccls Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -==============================================================================*/ - -#include "match.hh" - -#include "message_handler.hh" -#include "pipeline.hh" - -namespace ccls { -std::optional Matcher::Create(const std::string &search) { - try { - Matcher m; - m.regex_string = search; - m.regex = std::regex(search, std::regex_constants::ECMAScript | - std::regex_constants::icase | - std::regex_constants::optimize - // std::regex_constants::nosubs - ); - return m; - } catch (const std::exception &e) { - ShowMessageParam params; - params.type = MessageType::Error; - params.message = - "failed to parse EMCAScript regex " + search + " : " + e.what(); - pipeline::Notify(window_showMessage, params); - return std::nullopt; - } -} - -bool Matcher::IsMatch(const std::string &value) const { - // std::smatch match; - // return std::regex_match(value, match, regex); - return std::regex_search(value, regex, std::regex_constants::match_any); -} - -GroupMatch::GroupMatch(const std::vector &whitelist, - const std::vector &blacklist) { - for (const std::string &entry : whitelist) { - std::optional m = Matcher::Create(entry); - if (m) - this->whitelist.push_back(*m); - } - for (const std::string &entry : blacklist) { - std::optional m = Matcher::Create(entry); - if (m) - this->blacklist.push_back(*m); - } -} - -bool GroupMatch::IsMatch(const std::string &value, - std::string *match_failure_reason) const { - for (const Matcher &m : whitelist) - if (m.IsMatch(value)) - return true; - - for (const Matcher &m : blacklist) - if (m.IsMatch(value)) { - if (match_failure_reason) - *match_failure_reason = "blacklist \"" + m.regex_string + "\""; - return false; - } - - return true; -} -} // namespace ccls diff --git a/src/match.hh b/src/match.hh deleted file mode 100644 index f5ebb976..00000000 --- a/src/match.hh +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright 2017-2018 ccls Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -==============================================================================*/ - -#pragma once - -#include - -#include -#include -#include - -namespace ccls { -struct Matcher { - static std::optional Create(const std::string &search); - - bool IsMatch(const std::string &value) const; - - std::string regex_string; - std::regex regex; -}; - -// Check multiple |Matcher| instances at the same time. -struct GroupMatch { - GroupMatch(const std::vector &whitelist, - const std::vector &blacklist); - - bool IsMatch(const std::string &value, - std::string *match_failure_reason = nullptr) const; - - std::vector whitelist; - std::vector blacklist; -}; -} // namespace ccls diff --git a/src/message_handler.cc b/src/message_handler.cc index ee67ee6c..1acb97be 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -16,7 +16,6 @@ limitations under the License. #include "message_handler.hh" #include "log.hh" -#include "match.hh" #include "pipeline.hh" #include "project.hh" #include "query_utils.hh" @@ -275,7 +274,7 @@ void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) { g_config->highlight.blacklist); assert(file.def); if (wfile->buffer_content.size() > g_config->highlight.largeFileSize || - !match.IsMatch(file.def->path)) + !match.Matches(file.def->path)) return; // Group symbols together. diff --git a/src/messages/ccls_reload.cc b/src/messages/ccls_reload.cc index 0ec1bb85..d48d23c9 100644 --- a/src/messages/ccls_reload.cc +++ b/src/messages/ccls_reload.cc @@ -14,7 +14,6 @@ limitations under the License. ==============================================================================*/ #include "clang_complete.hh" -#include "match.hh" #include "message_handler.hh" #include "pipeline.hh" #include "project.hh" diff --git a/src/pipeline.cc b/src/pipeline.cc index c91f338d..fceb524d 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -20,7 +20,6 @@ limitations under the License. #include "include_complete.hh" #include "log.hh" #include "lsp.hh" -#include "match.hh" #include "message_handler.hh" #include "pipeline.hh" #include "platform.hh" @@ -199,7 +198,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, return false; } - if (!matcher.IsMatch(request.path)) { + if (!matcher.Matches(request.path)) { LOG_IF_S(INFO, loud) << "skip " << request.path; return false; } @@ -321,7 +320,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, for (std::unique_ptr &curr : indexes) { std::string path = curr->path; - if (!matcher.IsMatch(path)) { + if (!matcher.Matches(path)) { LOG_IF_S(INFO, loud) << "skip index for " << path; continue; } diff --git a/src/project.cc b/src/project.cc index eee0d774..3f1df407 100644 --- a/src/project.cc +++ b/src/project.cc @@ -18,7 +18,6 @@ limitations under the License. #include "clang_tu.hh" // llvm::vfs #include "filesystem.hh" #include "log.hh" -#include "match.hh" #include "pipeline.hh" #include "platform.hh" #include "serializers/json.hh" @@ -497,8 +496,8 @@ void Project::Index(WorkingFiles *wfiles, RequestId id) { int i = 0; for (const Project::Entry &entry : folder.entries) { std::string reason; - if (match.IsMatch(entry.filename, &reason) && - match_i.IsMatch(entry.filename, &reason)) { + if (match.Matches(entry.filename, &reason) && + match_i.Matches(entry.filename, &reason)) { bool interactive = wfiles->GetFileByFilename(entry.filename) != nullptr; pipeline::Index( diff --git a/src/utils.cc b/src/utils.cc index 3100c32d..48e9c0d0 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -16,6 +16,8 @@ limitations under the License. #include "utils.hh" #include "log.hh" +#include "message_handler.hh" +#include "pipeline.hh" #include "platform.hh" #include @@ -30,10 +32,67 @@ using namespace llvm; #include #include #include +#include #include #include namespace ccls { +struct Matcher::Impl { + std::regex regex; +}; + +Matcher::Matcher(const std::string &pattern) + : impl(std::make_unique()), pattern(pattern) { + impl->regex = std::regex(pattern, std::regex_constants::ECMAScript | + std::regex_constants::icase | + std::regex_constants::optimize); +} + +Matcher::~Matcher() {} + +bool Matcher::Matches(const std::string &text) const { + return std::regex_search(text, impl->regex, std::regex_constants::match_any); +} + +GroupMatch::GroupMatch(const std::vector &whitelist, + const std::vector &blacklist) { + auto err = [](const std::string &pattern, const char *what) { + ShowMessageParam params; + params.type = MessageType::Error; + params.message = + "failed to parse EMCAScript regex " + pattern + " : " + what; + pipeline::Notify(window_showMessage, params); + }; + for (const std::string &pattern : whitelist) { + try { + this->whitelist.emplace_back(pattern); + } catch (const std::exception &e) { + err(pattern, e.what()); + } + } + for (const std::string &pattern : blacklist) { + try { + this->blacklist.emplace_back(pattern); + } catch (const std::exception &e) { + err(pattern, e.what()); + } + } +} + +bool GroupMatch::Matches(const std::string &text, + std::string *blacklist_pattern) const { + for (const Matcher &m : whitelist) + if (m.Matches(text)) + return true; + for (const Matcher &m : blacklist) + if (m.Matches(text)) { + if (blacklist_pattern) + *blacklist_pattern = m.pattern; + return false; + } + return true; +} + uint64_t HashUsr(llvm::StringRef s) { union { uint64_t ret; diff --git a/src/utils.hh b/src/utils.hh index 1c00b2a6..d6d07966 100644 --- a/src/utils.hh +++ b/src/utils.hh @@ -19,6 +19,7 @@ limitations under the License. #include #include +#include #include #include @@ -27,6 +28,26 @@ class StringRef; } namespace ccls { +struct Matcher { + struct Impl; + std::unique_ptr impl; + std::string pattern; + + Matcher(const std::string &pattern); // throw + Matcher(Matcher&&) = default; + ~Matcher(); + bool Matches(const std::string &text) const; +}; + +struct GroupMatch { + std::vector whitelist, blacklist; + + GroupMatch(const std::vector &whitelist, + const std::vector &blacklist); + bool Matches(const std::string &text, + std::string *blacklist_pattern = nullptr) const; +}; + uint64_t HashUsr(llvm::StringRef s); std::string LowerPathIfInsensitive(const std::string &path);