source/model-generator/FieldConstraints.cpp (170 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <mariana-trench/model-generator/FieldConstraints.h>
#include <mariana-trench/model-generator/MethodConstraints.h>
namespace marianatrench {
IsStaticFieldConstraint::IsStaticFieldConstraint(bool expected)
: expected_(expected) {}
bool IsStaticFieldConstraint::satisfy(const Field* field) const {
return (field->dex_field()->get_access() & DexAccessFlags::ACC_STATIC) > 0 ==
expected_;
}
bool IsStaticFieldConstraint::operator==(const FieldConstraint& other) const {
if (auto* other_constraint =
dynamic_cast<const IsStaticFieldConstraint*>(&other)) {
return other_constraint->expected_ == expected_;
} else {
return false;
}
}
FieldNameConstraint::FieldNameConstraint(const std::string& regex_string)
: pattern_(regex_string) {}
bool FieldNameConstraint::satisfy(const Field* field) const {
return re2::RE2::FullMatch(field->get_name(), pattern_);
}
bool FieldNameConstraint::operator==(const FieldConstraint& other) const {
if (auto* other_constraint =
dynamic_cast<const FieldNameConstraint*>(&other)) {
return other_constraint->pattern_.pattern() == pattern_.pattern();
} else {
return false;
}
}
SignatureFieldConstraint::SignatureFieldConstraint(
const std::string& regex_string)
: pattern_(regex_string) {}
bool SignatureFieldConstraint::satisfy(const Field* field) const {
return re2::RE2::FullMatch(field->show(), pattern_);
}
bool SignatureFieldConstraint::operator==(const FieldConstraint& other) const {
if (auto* other_constraint =
dynamic_cast<const SignatureFieldConstraint*>(&other)) {
return other_constraint->pattern_.pattern() == pattern_.pattern();
} else {
return false;
}
}
HasAnnotationFieldConstraint::HasAnnotationFieldConstraint(
const std::string& type,
const std::optional<std::string>& annotation)
: type_(type), annotation_(annotation) {}
bool HasAnnotationFieldConstraint::satisfy(const Field* field) const {
return has_annotation(field->dex_field()->get_anno_set(), type_, annotation_);
}
bool HasAnnotationFieldConstraint::operator==(
const FieldConstraint& other) const {
if (auto* other_constraint =
dynamic_cast<const HasAnnotationFieldConstraint*>(&other)) {
return other_constraint->type_ == type_ &&
((!other_constraint->annotation_ && !annotation_) ||
(other_constraint->annotation_ && annotation_ &&
other_constraint->annotation_->pattern() == annotation_->pattern()));
} else {
return false;
}
}
ParentFieldConstraint::ParentFieldConstraint(
std::unique_ptr<TypeConstraint> inner_constraint)
: inner_constraint_(std::move(inner_constraint)) {}
bool ParentFieldConstraint::satisfy(const Field* field) const {
return inner_constraint_->satisfy(field->get_class());
}
bool ParentFieldConstraint::operator==(const FieldConstraint& other) const {
if (auto* other_constraint =
dynamic_cast<const ParentFieldConstraint*>(&other)) {
return *(other_constraint->inner_constraint_) == *inner_constraint_;
} else {
return false;
}
}
AllOfFieldConstraint::AllOfFieldConstraint(
std::vector<std::unique_ptr<FieldConstraint>> constraints)
: constraints_(std::move(constraints)) {}
bool AllOfFieldConstraint::satisfy(const Field* field) const {
return std::all_of(
constraints_.begin(),
constraints_.end(),
[field](const auto& constraint) { return constraint->satisfy(field); });
}
bool AllOfFieldConstraint::operator==(const FieldConstraint& other) const {
if (auto* other_constraint =
dynamic_cast<const AllOfFieldConstraint*>(&other)) {
return std::is_permutation(
other_constraint->constraints_.begin(),
other_constraint->constraints_.end(),
constraints_.begin(),
constraints_.end(),
[](const auto& left, const auto& right) { return *left == *right; });
} else {
return false;
}
}
AnyOfFieldConstraint::AnyOfFieldConstraint(
std::vector<std::unique_ptr<FieldConstraint>> constraints)
: constraints_(std::move(constraints)) {}
bool AnyOfFieldConstraint::satisfy(const Field* field) const {
// If there is no constraint, the field vacuously satisfies the constraint
// This is different from the semantic of std::any_of
if (constraints_.empty()) {
return true;
}
return std::any_of(
constraints_.begin(),
constraints_.end(),
[field](const auto& constraint) { return constraint->satisfy(field); });
}
bool AnyOfFieldConstraint::operator==(const FieldConstraint& other) const {
if (auto* other_constraint =
dynamic_cast<const AnyOfFieldConstraint*>(&other)) {
return std::is_permutation(
other_constraint->constraints_.begin(),
other_constraint->constraints_.end(),
constraints_.begin(),
constraints_.end(),
[](const auto& left, const auto& right) { return *left == *right; });
} else {
return false;
}
}
std::unique_ptr<FieldConstraint> FieldConstraint::from_json(
const Json::Value& constraint) {
JsonValidation::validate_object(constraint);
std::string constraint_name =
JsonValidation::string(constraint, "constraint");
if (constraint_name == "name") {
return std::make_unique<FieldNameConstraint>(
JsonValidation::string(constraint, /* field */ "pattern"));
} else if (constraint_name == "signature") {
return std::make_unique<SignatureFieldConstraint>(
JsonValidation::string(constraint, /* field */ "pattern"));
} else if (constraint_name == "is_static") {
bool expected = constraint.isMember("value")
? JsonValidation::boolean(constraint, /* field */ "value")
: true;
return std::make_unique<IsStaticFieldConstraint>(expected);
} else if (constraint_name == "any_of" || constraint_name == "all_of") {
std::vector<std::unique_ptr<FieldConstraint>> constraints;
for (const auto& inner :
JsonValidation::null_or_array(constraint, /* field */ "inners")) {
constraints.push_back(FieldConstraint::from_json(inner));
}
if (constraint_name == "any_of") {
return std::make_unique<AnyOfFieldConstraint>(std::move(constraints));
} else {
return std::make_unique<AllOfFieldConstraint>(std::move(constraints));
}
} else if (constraint_name == "has_annotation") {
return std::make_unique<HasAnnotationFieldConstraint>(
JsonValidation::string(constraint, "type"),
constraint.isMember("pattern")
? std::optional<std::string>{JsonValidation::string(
constraint, "pattern")}
: std::nullopt);
} else if (constraint_name == "parent") {
return std::make_unique<ParentFieldConstraint>(TypeConstraint::from_json(
JsonValidation::object(constraint, /* field */ "inner")));
} else {
throw JsonValidationError(
constraint,
/* field */ "constraint",
/* expected */ "valid field constraint type");
return nullptr;
}
}
} // namespace marianatrench