Refactor Matcher to use pimpl and merge match.hh into utils.hh

This commit is contained in:
Fangrui Song 2018-11-26 22:22:27 -08:00
parent e6510f7428
commit 5a723b489a
12 changed files with 90 additions and 140 deletions

View File

@ -190,7 +190,6 @@ target_sources(ccls PRIVATE
src/indexer.cc src/indexer.cc
src/log.cc src/log.cc
src/lsp.cc src/lsp.cc
src/match.cc
src/message_handler.cc src/message_handler.cc
src/pipeline.cc src/pipeline.cc
src/platform_posix.cc src/platform_posix.cc

View File

@ -18,7 +18,6 @@ limitations under the License.
#include "clang_tu.hh" #include "clang_tu.hh"
#include "filesystem.hh" #include "filesystem.hh"
#include "log.hh" #include "log.hh"
#include "match.hh"
#include "platform.hh" #include "platform.hh"
#include <clang/Lex/PreprocessorOptions.h> #include <clang/Lex/PreprocessorOptions.h>
@ -585,7 +584,7 @@ void CompletionManager::DiagnosticsUpdate(const std::string &path,
int debounce) { int debounce) {
static GroupMatch match(g_config->diagnostics.whitelist, static GroupMatch match(g_config->diagnostics.whitelist,
g_config->diagnostics.blacklist); g_config->diagnostics.blacklist);
if (!match.IsMatch(path)) if (!match.Matches(path))
return; return;
int64_t now = chrono::duration_cast<chrono::milliseconds>( int64_t now = chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now().time_since_epoch()) chrono::high_resolution_clock::now().time_since_epoch())

View File

@ -16,7 +16,6 @@ limitations under the License.
#include "include_complete.hh" #include "include_complete.hh"
#include "filesystem.hh" #include "filesystem.hh"
#include "match.hh"
#include "platform.hh" #include "platform.hh"
#include "project.hh" #include "project.hh"
@ -162,7 +161,7 @@ void IncludeComplete::AddFile(const std::string &path) {
ok = true; ok = true;
if (!ok) if (!ok)
return; return;
if (match_ && !match_->IsMatch(path)) if (match_ && !match_->Matches(path))
return; return;
std::string trimmed_path = path; std::string trimmed_path = path;
@ -179,7 +178,7 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
bool use_angle_brackets) { bool use_angle_brackets) {
directory = NormalizePath(directory); directory = NormalizePath(directory);
EnsureEndsInSlash(directory); EnsureEndsInSlash(directory);
if (match_ && !match_->IsMatch(directory)) if (match_ && !match_->Matches(directory))
return; return;
bool include_cpp = directory.find("include/c++") != std::string::npos; bool include_cpp = directory.find("include/c++") != std::string::npos;
@ -193,7 +192,7 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
ok = true; ok = true;
if (!ok) if (!ok)
return; return;
if (match_ && !match_->IsMatch(directory + path)) if (match_ && !match_->Matches(directory + path))
return; return;
CompletionCandidate candidate; CompletionCandidate candidate;

View File

@ -18,7 +18,6 @@ limitations under the License.
#include "clang_complete.hh" #include "clang_complete.hh"
#include "clang_tu.hh" #include "clang_tu.hh"
#include "log.hh" #include "log.hh"
#include "match.hh"
#include "pipeline.hh" #include "pipeline.hh"
#include "platform.hh" #include "platform.hh"
#include "serializer.hh" #include "serializer.hh"
@ -97,7 +96,7 @@ struct IndexParam {
bool UseMultiVersion(const FileEntry &FE) { bool UseMultiVersion(const FileEntry &FE) {
auto it = UID2multi.try_emplace(FE.getUniqueID()); auto it = UID2multi.try_emplace(FE.getUniqueID());
if (it.second) if (it.second)
it.first->second = multiVersionMatcher->IsMatch(PathFromFileEntry(FE)); it.first->second = multiVersionMatcher->Matches(PathFromFileEntry(FE));
return it.first->second; return it.first->second;
} }
}; };

View File

@ -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> 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<std::string> &whitelist,
const std::vector<std::string> &blacklist) {
for (const std::string &entry : whitelist) {
std::optional<Matcher> m = Matcher::Create(entry);
if (m)
this->whitelist.push_back(*m);
}
for (const std::string &entry : blacklist) {
std::optional<Matcher> 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

View File

@ -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 <optional>
#include <regex>
#include <string>
#include <vector>
namespace ccls {
struct Matcher {
static std::optional<Matcher> 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<std::string> &whitelist,
const std::vector<std::string> &blacklist);
bool IsMatch(const std::string &value,
std::string *match_failure_reason = nullptr) const;
std::vector<Matcher> whitelist;
std::vector<Matcher> blacklist;
};
} // namespace ccls

View File

@ -16,7 +16,6 @@ limitations under the License.
#include "message_handler.hh" #include "message_handler.hh"
#include "log.hh" #include "log.hh"
#include "match.hh"
#include "pipeline.hh" #include "pipeline.hh"
#include "project.hh" #include "project.hh"
#include "query_utils.hh" #include "query_utils.hh"
@ -275,7 +274,7 @@ void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
g_config->highlight.blacklist); g_config->highlight.blacklist);
assert(file.def); assert(file.def);
if (wfile->buffer_content.size() > g_config->highlight.largeFileSize || if (wfile->buffer_content.size() > g_config->highlight.largeFileSize ||
!match.IsMatch(file.def->path)) !match.Matches(file.def->path))
return; return;
// Group symbols together. // Group symbols together.

View File

@ -14,7 +14,6 @@ limitations under the License.
==============================================================================*/ ==============================================================================*/
#include "clang_complete.hh" #include "clang_complete.hh"
#include "match.hh"
#include "message_handler.hh" #include "message_handler.hh"
#include "pipeline.hh" #include "pipeline.hh"
#include "project.hh" #include "project.hh"

View File

@ -20,7 +20,6 @@ limitations under the License.
#include "include_complete.hh" #include "include_complete.hh"
#include "log.hh" #include "log.hh"
#include "lsp.hh" #include "lsp.hh"
#include "match.hh"
#include "message_handler.hh" #include "message_handler.hh"
#include "pipeline.hh" #include "pipeline.hh"
#include "platform.hh" #include "platform.hh"
@ -199,7 +198,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles,
return false; return false;
} }
if (!matcher.IsMatch(request.path)) { if (!matcher.Matches(request.path)) {
LOG_IF_S(INFO, loud) << "skip " << request.path; LOG_IF_S(INFO, loud) << "skip " << request.path;
return false; return false;
} }
@ -321,7 +320,7 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles,
for (std::unique_ptr<IndexFile> &curr : indexes) { for (std::unique_ptr<IndexFile> &curr : indexes) {
std::string path = curr->path; std::string path = curr->path;
if (!matcher.IsMatch(path)) { if (!matcher.Matches(path)) {
LOG_IF_S(INFO, loud) << "skip index for " << path; LOG_IF_S(INFO, loud) << "skip index for " << path;
continue; continue;
} }

View File

@ -18,7 +18,6 @@ limitations under the License.
#include "clang_tu.hh" // llvm::vfs #include "clang_tu.hh" // llvm::vfs
#include "filesystem.hh" #include "filesystem.hh"
#include "log.hh" #include "log.hh"
#include "match.hh"
#include "pipeline.hh" #include "pipeline.hh"
#include "platform.hh" #include "platform.hh"
#include "serializers/json.hh" #include "serializers/json.hh"
@ -497,8 +496,8 @@ void Project::Index(WorkingFiles *wfiles, RequestId id) {
int i = 0; int i = 0;
for (const Project::Entry &entry : folder.entries) { for (const Project::Entry &entry : folder.entries) {
std::string reason; std::string reason;
if (match.IsMatch(entry.filename, &reason) && if (match.Matches(entry.filename, &reason) &&
match_i.IsMatch(entry.filename, &reason)) { match_i.Matches(entry.filename, &reason)) {
bool interactive = bool interactive =
wfiles->GetFileByFilename(entry.filename) != nullptr; wfiles->GetFileByFilename(entry.filename) != nullptr;
pipeline::Index( pipeline::Index(

View File

@ -16,6 +16,8 @@ limitations under the License.
#include "utils.hh" #include "utils.hh"
#include "log.hh" #include "log.hh"
#include "message_handler.hh"
#include "pipeline.hh"
#include "platform.hh" #include "platform.hh"
#include <siphash.h> #include <siphash.h>
@ -30,10 +32,67 @@ using namespace llvm;
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <functional> #include <functional>
#include <regex>
#include <string.h> #include <string.h>
#include <unordered_map> #include <unordered_map>
namespace ccls { namespace ccls {
struct Matcher::Impl {
std::regex regex;
};
Matcher::Matcher(const std::string &pattern)
: impl(std::make_unique<Impl>()), 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<std::string> &whitelist,
const std::vector<std::string> &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) { uint64_t HashUsr(llvm::StringRef s) {
union { union {
uint64_t ret; uint64_t ret;

View File

@ -19,6 +19,7 @@ limitations under the License.
#include <string_view> #include <string_view>
#include <iterator> #include <iterator>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -27,6 +28,26 @@ class StringRef;
} }
namespace ccls { namespace ccls {
struct Matcher {
struct Impl;
std::unique_ptr<Impl> 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<Matcher> whitelist, blacklist;
GroupMatch(const std::vector<std::string> &whitelist,
const std::vector<std::string> &blacklist);
bool Matches(const std::string &text,
std::string *blacklist_pattern = nullptr) const;
};
uint64_t HashUsr(llvm::StringRef s); uint64_t HashUsr(llvm::StringRef s);
std::string LowerPathIfInsensitive(const std::string &path); std::string LowerPathIfInsensitive(const std::string &path);