/* * Copyright (C) 2021 The Android Open Source Project * * 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 "tools/proto_merger/proto_file_serializer.h" #include "perfetto/ext/base/string_utils.h" namespace perfetto { namespace proto_merger { namespace { std::string DeletedComment(const std::string& prefix) { std::string output; output += "\n"; output += prefix + " //\n"; output += prefix; output += " // The following enums/messages/fields are not present upstream\n"; output += prefix + " //\n"; return output; } std::string SerializeComments(const std::string& prefix, const std::vector& lines) { std::string output; for (const auto& line : lines) { output.append(prefix); output.append("//"); output.append(line); output.append("\n"); } return output; } std::string SerializeLeadingComments(const std::string& prefix, const ProtoFile::Member& member, bool prefix_newline_if_comment = true) { if (member.leading_comments.empty()) return ""; std::string output; if (prefix_newline_if_comment) { output += "\n"; } output += SerializeComments(prefix, member.leading_comments); return output; } std::string SerializeTrailingComments(const std::string& prefix, const ProtoFile::Member& member) { return SerializeComments(prefix, member.trailing_comments); } std::string SerializeOptions(const std::vector& options) { if (options.empty()) return ""; std::string output; output += " ["; for (const auto& option : options) { output += option.key + " = " + option.value; } output += "]"; return output; } std::string SerializeEnumValue(size_t indent, const ProtoFile::Enum::Value& value) { std::string prefix(indent * 2, ' '); std::string output; output += SerializeLeadingComments(prefix, value, false); output += prefix + value.name + " = " + std::to_string(value.number); output += SerializeOptions(value.options); output += ";\n"; output += SerializeTrailingComments(prefix, value); return output; } std::string SerializeEnum(size_t indent, const ProtoFile::Enum& en) { std::string prefix(indent * 2, ' '); ++indent; std::string output; output += SerializeLeadingComments(prefix, en); output += prefix + "enum " + en.name + " {\n"; for (const auto& value : en.values) { output += SerializeEnumValue(indent, value); } output += prefix + "}\n"; output += SerializeTrailingComments(prefix, en); return output; } std::string SerializeField(size_t indent, const ProtoFile::Field& field, bool write_label) { std::string prefix(indent * 2, ' '); std::string output; output += SerializeLeadingComments(prefix, field); std::string label; if (write_label) { label = field.label + " "; } output += prefix + label + field.type + " " + field.name + " = " + std::to_string(field.number); output += SerializeOptions(field.options); output += ";\n"; output += SerializeTrailingComments(prefix, field); return output; } std::string SerializeOneof(size_t indent, const ProtoFile::Oneof& oneof) { std::string prefix(indent * 2, ' '); ++indent; std::string output; output += SerializeLeadingComments(prefix, oneof); output += prefix + "oneof " + oneof.name + " {\n"; for (const auto& field : oneof.fields) { output += SerializeField(indent, field, false); } output += prefix + "}\n"; output += SerializeTrailingComments(prefix, oneof); return output; } std::string SerializeMessage(size_t indent, const ProtoFile::Message& message) { std::string prefix(indent * 2, ' '); ++indent; std::string output; output += SerializeLeadingComments(prefix, message); output += prefix + "message " + message.name + " {\n"; for (const auto& en : message.enums) { output += SerializeEnum(indent, en); } for (const auto& nested : message.nested_messages) { output += SerializeMessage(indent, nested); } for (const auto& oneof : message.oneofs) { output += SerializeOneof(indent, oneof); } for (const auto& field : message.fields) { output += SerializeField(indent, field, true); } if (!message.deleted_enums.empty() || !message.deleted_fields.empty() || !message.deleted_nested_messages.empty() || !message.deleted_oneofs.empty()) { output += DeletedComment(prefix); for (const auto& en : message.deleted_enums) { output += SerializeEnum(indent, en); } for (const auto& nested : message.deleted_nested_messages) { output += SerializeMessage(indent, nested); } for (const auto& oneof : message.deleted_oneofs) { output += SerializeOneof(indent, oneof); } for (const auto& field : message.deleted_fields) { output += SerializeField(indent, field, true); } } output += prefix + "}\n"; output += SerializeTrailingComments(prefix, message); return output; } } // namespace std::string ProtoFileToDotProto(const ProtoFile& proto_file) { std::string output; for (const auto& en : proto_file.enums) { output += SerializeEnum(0, en); } for (const auto& message : proto_file.messages) { output += SerializeMessage(0, message); } if (!proto_file.deleted_enums.empty() || !proto_file.deleted_messages.empty()) { output += DeletedComment(""); for (const auto& en : proto_file.deleted_enums) { output += SerializeEnum(0, en); } for (const auto& nested : proto_file.deleted_messages) { output += SerializeMessage(0, nested); } } return output; } } // namespace proto_merger } // namespace perfetto