blob: b291599464a3169aca0cf34d5a01a86534707095 [file] [log] [blame] [edit]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/expr/identifier_glob.h"
#include <optional>
#include "src/developer/debug/zxdb/expr/expr_parser.h"
namespace zxdb {
namespace {
// Matches the template parameters of one component. Return value is the same as
// IdentifierGlob::Matches.
std::optional<int> MatchTemplateParams(const std::vector<std::string>& glob,
const std::vector<std::string>& type) {
if (type.size() < glob.size())
return std::nullopt; // Glob trying to match more parameters than the type has.
int last_score = 0;
for (size_t i = 0; i < glob.size(); i++) {
if (glob[i] == "*") {
if (i == glob.size() - 1) {
// Last glob "*" matches all remaining type parameters.
last_score = static_cast<int>(type.size()) - i;
break;
} else {
last_score = 1;
}
} else {
// Non-wildcards must be an exact match.
if (glob[i] != type[i])
return std::nullopt;
// Last glob template was not a wildcard, and there are still more type params to match.
if (i == glob.size() - 1 && type.size() > glob.size())
return std::nullopt;
}
}
return last_score;
}
std::optional<int> MatchNamespaceComponents(const std::vector<ParsedIdentifierComponent>& glob,
const std::vector<ParsedIdentifierComponent>& type) {
if (glob.back().name() == type.back().name()) {
return type.size() - 1;
}
return std::nullopt;
}
} // namespace
Err IdentifierGlob::Init(const std::string& glob) { return Init(glob, false); }
Err IdentifierGlob::Init(const std::string& glob, bool match_any_namespace) {
match_any_namespace_ = match_any_namespace;
return ExprParser::ParseIdentifier(glob, &parsed_);
}
std::optional<int> IdentifierGlob::Matches(const ParsedIdentifier& type) const {
if (type.components().empty())
return std::nullopt;
// Without any template parameters or qualifications, we match the last component of the actual
// type on the parsed name.
if (match_any_namespace_) {
if (!type.components().back().has_template() && !parsed_.components().back().has_template()) {
// We should never have |match_any_namespace_| be true for a glob with more than one
// component.
FX_DCHECK(parsed_.components().size() == 1);
return MatchNamespaceComponents(parsed_.components(), type.components());
}
}
if (parsed_.components().size() != type.components().size())
return std::nullopt;
int max_component_score = 0;
for (size_t i = 0; i < type.components().size(); i++) {
// The name must match exactly.
if (parsed_.components()[i].name() != type.components()[i].name() ||
parsed_.components()[i].has_template() != type.components()[i].has_template())
return std::nullopt;
if (parsed_.components()[i].has_template()) {
// Check template parameters.
if (auto score = MatchTemplateParams(parsed_.components()[i].template_contents(),
type.components()[i].template_contents())) {
// Want the largest score.
if (*score > max_component_score)
max_component_score = *score;
} else {
return std::nullopt; // Template params don't match.
}
}
}
return max_component_score;
}
} // namespace zxdb