xref: /aosp_15_r20/external/perfetto/src/tools/proto_merger/proto_file_serializer.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/tools/proto_merger/proto_file_serializer.h"
18 
19 #include "perfetto/ext/base/string_utils.h"
20 
21 namespace perfetto {
22 namespace proto_merger {
23 namespace {
24 
DeletedComment(const std::string & prefix)25 std::string DeletedComment(const std::string& prefix) {
26   std::string output;
27   output += "\n";
28   output += prefix + "  //\n";
29   output += prefix;
30   output +=
31       "  // The following enums/messages/fields are not present upstream\n";
32   output += prefix + "  //\n";
33   return output;
34 }
35 
SerializeComments(const std::string & prefix,const std::vector<std::string> & lines)36 std::string SerializeComments(const std::string& prefix,
37                               const std::vector<std::string>& lines) {
38   std::string output;
39   for (const auto& line : lines) {
40     output.append(prefix);
41     output.append("//");
42     output.append(line);
43     output.append("\n");
44   }
45   return output;
46 }
47 
SerializeLeadingComments(const std::string & prefix,const ProtoFile::Member & member,bool prefix_newline_if_comment=true)48 std::string SerializeLeadingComments(const std::string& prefix,
49                                      const ProtoFile::Member& member,
50                                      bool prefix_newline_if_comment = true) {
51   if (member.leading_comments.empty())
52     return "";
53 
54   std::string output;
55   if (prefix_newline_if_comment) {
56     output += "\n";
57   }
58   output += SerializeComments(prefix, member.leading_comments);
59   return output;
60 }
61 
SerializeTrailingComments(const std::string & prefix,const ProtoFile::Member & member)62 std::string SerializeTrailingComments(const std::string& prefix,
63                                       const ProtoFile::Member& member) {
64   return SerializeComments(prefix, member.trailing_comments);
65 }
66 
SerializeOptions(const std::vector<ProtoFile::Option> & options)67 std::string SerializeOptions(const std::vector<ProtoFile::Option>& options) {
68   if (options.empty())
69     return "";
70 
71   std::string output;
72   output += " [";
73   size_t n = options.size();
74   for (size_t i = 0; i < n; i++) {
75     output += options[i].key + " = " + options[i].value;
76     if (i != n - 1)
77       output += ", ";
78   }
79   output += "]";
80   return output;
81 }
82 
SerializeEnumValue(size_t indent,const ProtoFile::Enum::Value & value)83 std::string SerializeEnumValue(size_t indent,
84                                const ProtoFile::Enum::Value& value) {
85   std::string prefix(indent * 2, ' ');
86 
87   std::string output;
88   output += SerializeLeadingComments(prefix, value, false);
89 
90   output += prefix + value.name + " = " + std::to_string(value.number);
91   output += SerializeOptions(value.options);
92   output += ";\n";
93 
94   output += SerializeTrailingComments(prefix, value);
95   return output;
96 }
97 
SerializeEnum(size_t indent,const ProtoFile::Enum & en)98 std::string SerializeEnum(size_t indent, const ProtoFile::Enum& en) {
99   std::string prefix(indent * 2, ' ');
100   ++indent;
101 
102   std::string output;
103   output += SerializeLeadingComments(prefix, en);
104 
105   output += prefix + "enum " + en.name + " {\n";
106   for (const auto& value : en.values) {
107     output += SerializeEnumValue(indent, value);
108   }
109   output += prefix + "}\n";
110 
111   output += SerializeTrailingComments(prefix, en);
112   return output;
113 }
114 
SerializeField(size_t indent,const ProtoFile::Field & field,bool write_label)115 std::string SerializeField(size_t indent,
116                            const ProtoFile::Field& field,
117                            bool write_label) {
118   std::string prefix(indent * 2, ' ');
119 
120   std::string output;
121   output += SerializeLeadingComments(prefix, field);
122 
123   output += prefix;
124   if (write_label && field.is_repeated)
125     output += "repeated ";
126   output +=
127       field.type + " " + field.name + " = " + std::to_string(field.number);
128 
129   output += SerializeOptions(field.options);
130   output += ";\n";
131 
132   output += SerializeTrailingComments(prefix, field);
133   return output;
134 }
135 
SerializeOneof(size_t indent,const ProtoFile::Oneof & oneof)136 std::string SerializeOneof(size_t indent, const ProtoFile::Oneof& oneof) {
137   std::string prefix(indent * 2, ' ');
138   ++indent;
139 
140   std::string output;
141   output += SerializeLeadingComments(prefix, oneof);
142 
143   output += prefix + "oneof " + oneof.name + " {\n";
144   for (const auto& field : oneof.fields) {
145     output += SerializeField(indent, field, false);
146   }
147   output += prefix + "}\n";
148 
149   output += SerializeTrailingComments(prefix, oneof);
150   return output;
151 }
152 
SerializeMessage(size_t indent,const ProtoFile::Message & message)153 std::string SerializeMessage(size_t indent, const ProtoFile::Message& message) {
154   std::string prefix(indent * 2, ' ');
155   ++indent;
156 
157   std::string output;
158   output += SerializeLeadingComments(prefix, message);
159 
160   output += prefix + "message " + message.name + " {\n";
161   for (const auto& en : message.enums) {
162     output += SerializeEnum(indent, en);
163   }
164   for (const auto& nested : message.nested_messages) {
165     output += SerializeMessage(indent, nested);
166   }
167   for (const auto& oneof : message.oneofs) {
168     output += SerializeOneof(indent, oneof);
169   }
170   for (const auto& field : message.fields) {
171     output += SerializeField(indent, field, true);
172   }
173 
174   if (!message.deleted_enums.empty() || !message.deleted_fields.empty() ||
175       !message.deleted_nested_messages.empty() ||
176       !message.deleted_oneofs.empty()) {
177     output += DeletedComment(prefix);
178     for (const auto& en : message.deleted_enums) {
179       output += SerializeEnum(indent, en);
180     }
181     for (const auto& nested : message.deleted_nested_messages) {
182       output += SerializeMessage(indent, nested);
183     }
184     for (const auto& oneof : message.deleted_oneofs) {
185       output += SerializeOneof(indent, oneof);
186     }
187     for (const auto& field : message.deleted_fields) {
188       output += SerializeField(indent, field, true);
189     }
190   }
191 
192   output += prefix + "}\n";
193 
194   output += SerializeTrailingComments(prefix, message);
195   return output;
196 }
197 
198 }  // namespace
199 
ProtoFileToDotProto(const ProtoFile & proto_file)200 std::string ProtoFileToDotProto(const ProtoFile& proto_file) {
201   std::string output;
202   output += proto_file.preamble;
203 
204   for (const auto& en : proto_file.enums) {
205     output += SerializeEnum(0, en);
206   }
207   for (const auto& message : proto_file.messages) {
208     output += SerializeMessage(0, message);
209   }
210 
211   if (!proto_file.deleted_enums.empty() ||
212       !proto_file.deleted_messages.empty()) {
213     output += DeletedComment("");
214 
215     for (const auto& en : proto_file.deleted_enums) {
216       output += SerializeEnum(0, en);
217     }
218     for (const auto& nested : proto_file.deleted_messages) {
219       output += SerializeMessage(0, nested);
220     }
221   }
222   return output;
223 }
224 
225 }  // namespace proto_merger
226 }  // namespace perfetto
227