source/model-generator/JsonModelGenerator.cpp (186 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/EventLogger.h> #include <mariana-trench/JsonValidation.h> #include <mariana-trench/Log.h> #include <mariana-trench/model-generator/JsonModelGenerator.h> namespace marianatrench { JsonModelGeneratorItem::JsonModelGeneratorItem( const std::string& name, Context& context, std::unique_ptr<AllOfMethodConstraint> constraint, ModelTemplate model_template, int verbosity) : MethodVisitorModelGenerator(name, context), constraint_(std::move(constraint)), model_template_(std::move(model_template)), verbosity_(verbosity) {} std::vector<Model> JsonModelGeneratorItem::emit_method_models_filtered( const MethodHashedSet& methods) { return this->run_impl(methods.elements().begin(), methods.elements().end()); } std::vector<Model> JsonModelGeneratorItem::visit_method( const Method* method) const { std::vector<Model> models; if (constraint_->satisfy(method)) { LOG(verbosity_, "Method `{}{}` satisfies all constraints in json model generator {}", method->is_static() ? "(static) " : "", method->show(), name_); auto model = model_template_.instantiate(context_, method); // If a method has an empty model, then don't add a model if (model) { models.push_back(*model); } } return models; } std::unordered_set<const MethodConstraint*> JsonModelGeneratorItem::constraint_leaves() const { std::unordered_set<const MethodConstraint*> flattened_constraints; std::vector<const MethodConstraint*> constraints = constraint_->children(); while (!constraints.empty()) { const MethodConstraint* constraint = constraints.back(); constraints.pop_back(); if (constraint->has_children()) { const std::vector<const MethodConstraint*> children = constraint->children(); for (const auto* child : children) { constraints.push_back(child); } } else { flattened_constraints.insert(constraint); } } return flattened_constraints; } MethodHashedSet JsonModelGeneratorItem::may_satisfy( const MethodMappings& method_mappings) const { return constraint_->may_satisfy(method_mappings); } JsonFieldModelGeneratorItem::JsonFieldModelGeneratorItem( const std::string& name, Context& context, std::unique_ptr<AllOfFieldConstraint> constraint, FieldModelTemplate field_model_template, int verbosity) : FieldVisitorModelGenerator(name, context), constraint_(std::move(constraint)), field_model_template_(std::move(field_model_template)), verbosity_(verbosity) {} std::vector<FieldModel> JsonFieldModelGeneratorItem::visit_field( const Field* field) const { std::vector<FieldModel> field_models; if (constraint_->satisfy(field)) { LOG(verbosity_, "Field `{}` satisfies all constraints in json model generator {}", field->show(), name_); auto field_model = field_model_template_.instantiate(field); // If a field has an empty model, then don't add it if (field_model) { field_models.push_back(*field_model); } } return field_models; } JsonModelGenerator::JsonModelGenerator( const std::string& name, Context& context, const boost::filesystem::path& json_configuration_file) : ModelGenerator(name, context), json_configuration_file_(json_configuration_file) { const Json::Value& value = JsonValidation::parse_json_file(json_configuration_file); JsonValidation::validate_object(value); for (auto model_generator : JsonValidation::nonempty_array(value, /* field */ "model_generators")) { int verbosity = model_generator.isMember("verbosity") ? JsonValidation::integer(model_generator, "verbosity") : 5; // default verbosity std::string find_name = JsonValidation::string(model_generator, "find"); if (find_name == "methods") { std::vector<std::unique_ptr<MethodConstraint>> model_constraints; for (auto constraint : JsonValidation::null_or_array( model_generator, /* field */ "where")) { model_constraints.push_back( MethodConstraint::from_json(constraint, context)); } items_.push_back(JsonModelGeneratorItem( name, context, std::make_unique<AllOfMethodConstraint>(std::move(model_constraints)), ModelTemplate::from_json( JsonValidation::object(model_generator, /* field */ "model"), context), verbosity)); } else if (find_name == "fields") { std::vector<std::unique_ptr<FieldConstraint>> field_model_constraints; for (auto constraint : JsonValidation::null_or_array( model_generator, /* field */ "where")) { field_model_constraints.push_back( FieldConstraint::from_json(constraint)); } field_items_.push_back(JsonFieldModelGeneratorItem( name, context, std::make_unique<AllOfFieldConstraint>( std::move(field_model_constraints)), FieldModelTemplate::from_json( JsonValidation::object(model_generator, /* field */ "model"), context), verbosity)); } else { ERROR(1, "Models for `{}` are not supported.", find_name); } } } std::vector<Model> JsonModelGenerator::emit_method_models( const Methods& methods) { std::vector<Model> models; for (auto& item : items_) { std::vector<Model> method_models = item.emit_method_models(methods); models.insert( models.end(), std::make_move_iterator(method_models.begin()), std::make_move_iterator(method_models.end())); } return models; } std::vector<Model> JsonModelGenerator::emit_method_models_optimized( const Methods& methods, const MethodMappings& method_mappings) { std::vector<Model> models; for (size_t i = 0; i < items_.size(); ++i) { auto& item = items_[i]; MethodHashedSet filtered_methods = item.may_satisfy(method_mappings); if (filtered_methods.is_bottom()) { continue; } std::vector<Model> method_models; if (filtered_methods.is_top()) { method_models = item.emit_method_models(methods); } else { method_models = item.emit_method_models_filtered(filtered_methods); } EventLogger::log_event( "model_generator_match", fmt::format("{}:{}", this->name(), i), method_models.size()); models.insert( models.end(), std::make_move_iterator(method_models.begin()), std::make_move_iterator(method_models.end())); } return models; } std::vector<FieldModel> JsonModelGenerator::emit_field_models( const Fields& fields) { std::vector<FieldModel> models; for (auto& item : field_items_) { std::vector<FieldModel> field_models = item.emit_field_models(fields); models.insert( models.end(), std::make_move_iterator(field_models.begin()), std::make_move_iterator(field_models.end())); } return models; } } // namespace marianatrench