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 std::string label;
124 if (write_label) {
125 label = field.label + " ";
126 }
127 output += prefix + label + field.type + " " + field.name + " = " +
128 std::to_string(field.number);
129
130 output += SerializeOptions(field.options);
131 output += ";\n";
132
133 output += SerializeTrailingComments(prefix, field);
134 return output;
135 }
136
SerializeOneof(size_t indent,const ProtoFile::Oneof & oneof)137 std::string SerializeOneof(size_t indent, const ProtoFile::Oneof& oneof) {
138 std::string prefix(indent * 2, ' ');
139 ++indent;
140
141 std::string output;
142 output += SerializeLeadingComments(prefix, oneof);
143
144 output += prefix + "oneof " + oneof.name + " {\n";
145 for (const auto& field : oneof.fields) {
146 output += SerializeField(indent, field, false);
147 }
148 output += prefix + "}\n";
149
150 output += SerializeTrailingComments(prefix, oneof);
151 return output;
152 }
153
SerializeMessage(size_t indent,const ProtoFile::Message & message)154 std::string SerializeMessage(size_t indent, const ProtoFile::Message& message) {
155 std::string prefix(indent * 2, ' ');
156 ++indent;
157
158 std::string output;
159 output += SerializeLeadingComments(prefix, message);
160
161 output += prefix + "message " + message.name + " {\n";
162 for (const auto& en : message.enums) {
163 output += SerializeEnum(indent, en);
164 }
165 for (const auto& nested : message.nested_messages) {
166 output += SerializeMessage(indent, nested);
167 }
168 for (const auto& oneof : message.oneofs) {
169 output += SerializeOneof(indent, oneof);
170 }
171 for (const auto& field : message.fields) {
172 output += SerializeField(indent, field, true);
173 }
174
175 if (!message.deleted_enums.empty() || !message.deleted_fields.empty() ||
176 !message.deleted_nested_messages.empty() ||
177 !message.deleted_oneofs.empty()) {
178 output += DeletedComment(prefix);
179 for (const auto& en : message.deleted_enums) {
180 output += SerializeEnum(indent, en);
181 }
182 for (const auto& nested : message.deleted_nested_messages) {
183 output += SerializeMessage(indent, nested);
184 }
185 for (const auto& oneof : message.deleted_oneofs) {
186 output += SerializeOneof(indent, oneof);
187 }
188 for (const auto& field : message.deleted_fields) {
189 output += SerializeField(indent, field, true);
190 }
191 }
192
193 output += prefix + "}\n";
194
195 output += SerializeTrailingComments(prefix, message);
196 return output;
197 }
198
199 } // namespace
200
ProtoFileToDotProto(const ProtoFile & proto_file)201 std::string ProtoFileToDotProto(const ProtoFile& proto_file) {
202 std::string output;
203 output += proto_file.preamble;
204
205 for (const auto& en : proto_file.enums) {
206 output += SerializeEnum(0, en);
207 }
208 for (const auto& message : proto_file.messages) {
209 output += SerializeMessage(0, message);
210 }
211
212 if (!proto_file.deleted_enums.empty() ||
213 !proto_file.deleted_messages.empty()) {
214 output += DeletedComment("");
215
216 for (const auto& en : proto_file.deleted_enums) {
217 output += SerializeEnum(0, en);
218 }
219 for (const auto& nested : proto_file.deleted_messages) {
220 output += SerializeMessage(0, nested);
221 }
222 }
223 return output;
224 }
225
226 } // namespace proto_merger
227 } // namespace perfetto
228