]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/parse/t_program.h
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / parse / t_program.h
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #ifndef T_PROGRAM_H
21 #define T_PROGRAM_H
22
23 #include <map>
24 #include <string>
25 #include <vector>
26
27 // For program_name()
28 #include "thrift/main.h"
29
30 #include "thrift/parse/t_doc.h"
31 #include "thrift/parse/t_scope.h"
32 #include "thrift/parse/t_base_type.h"
33 #include "thrift/parse/t_typedef.h"
34 #include "thrift/parse/t_enum.h"
35 #include "thrift/parse/t_const.h"
36 #include "thrift/parse/t_struct.h"
37 #include "thrift/parse/t_service.h"
38 #include "thrift/parse/t_list.h"
39 #include "thrift/parse/t_map.h"
40 #include "thrift/parse/t_set.h"
41 #include "thrift/generate/t_generator_registry.h"
42 //#include "thrift/parse/t_doc.h"
43
44 /**
45 * Top level class representing an entire thrift program. A program consists
46 * fundamentally of the following:
47 *
48 * Typedefs
49 * Enumerations
50 * Constants
51 * Structs
52 * Exceptions
53 * Services
54 *
55 * The program module also contains the definitions of the base types.
56 *
57 */
58 class t_program : public t_doc {
59 public:
60 t_program(std::string path, std::string name)
61 : path_(path), name_(name), out_path_("./"), out_path_is_absolute_(false), scope_(new t_scope), recursive_(false) {}
62
63 t_program(std::string path) : path_(path), out_path_("./"), out_path_is_absolute_(false), recursive_(false) {
64 name_ = program_name(path);
65 scope_ = new t_scope();
66 }
67
68 ~t_program() override {
69 if (scope_) {
70 delete scope_;
71 scope_ = nullptr;
72 }
73 }
74
75 // Path accessor
76 const std::string& get_path() const { return path_; }
77
78 // Output path accessor
79 const std::string& get_out_path() const { return out_path_; }
80
81 // Create gen-* dir accessor
82 bool is_out_path_absolute() const { return out_path_is_absolute_; }
83
84 // Name accessor
85 const std::string& get_name() const { return name_; }
86
87 // Namespace
88 const std::string& get_namespace() const { return namespace_; }
89
90 // Include prefix accessor
91 const std::string& get_include_prefix() const { return include_prefix_; }
92
93 // Accessors for program elements
94 const std::vector<t_typedef*>& get_typedefs() const { return typedefs_; }
95 const std::vector<t_enum*>& get_enums() const { return enums_; }
96 const std::vector<t_const*>& get_consts() const { return consts_; }
97 const std::vector<t_struct*>& get_structs() const { return structs_; }
98 const std::vector<t_struct*>& get_xceptions() const { return xceptions_; }
99 const std::vector<t_struct*>& get_objects() const { return objects_; }
100 const std::vector<t_service*>& get_services() const { return services_; }
101 const std::map<std::string, std::string>& get_namespaces() const { return namespaces_; }
102
103 // Program elements
104 void add_typedef(t_typedef* td) { typedefs_.push_back(td); }
105 void add_enum(t_enum* te) { enums_.push_back(te); }
106 void add_const(t_const* tc) { consts_.push_back(tc); }
107 void add_struct(t_struct* ts) {
108 objects_.push_back(ts);
109 structs_.push_back(ts);
110 }
111 void add_xception(t_struct* tx) {
112 objects_.push_back(tx);
113 xceptions_.push_back(tx);
114 }
115 void add_service(t_service* ts) { services_.push_back(ts); }
116
117 // Programs to include
118 std::vector<t_program*>& get_includes() { return includes_; }
119
120 const std::vector<t_program*>& get_includes() const { return includes_; }
121
122 void set_out_path(std::string out_path, bool out_path_is_absolute) {
123 out_path_ = out_path;
124 out_path_is_absolute_ = out_path_is_absolute;
125 // Ensure that it ends with a trailing '/' (or '\' for windows machines)
126 char c = out_path_.at(out_path_.size() - 1);
127 if (!(c == '/' || c == '\\')) {
128 out_path_.push_back('/');
129 }
130 }
131
132 // Typename collision detection
133 /**
134 * Search for typename collisions
135 * @param t the type to test for collisions
136 * @return true if a certain collision was found, otherwise false
137 */
138 bool is_unique_typename(const t_type* t) const {
139 int occurrences = program_typename_count(this, t);
140 for (auto it = includes_.cbegin(); it != includes_.cend(); ++it) {
141 occurrences += program_typename_count(*it, t);
142 }
143 return 0 == occurrences;
144 }
145
146 /**
147 * Search all type collections for duplicate typenames
148 * @param prog the program to search
149 * @param t the type to test for collisions
150 * @return the number of certain typename collisions
151 */
152 int program_typename_count(const t_program* prog, const t_type* t) const {
153 int occurrences = 0;
154 occurrences += collection_typename_count(prog, prog->typedefs_, t);
155 occurrences += collection_typename_count(prog, prog->enums_, t);
156 occurrences += collection_typename_count(prog, prog->objects_, t);
157 occurrences += collection_typename_count(prog, prog->services_, t);
158 return occurrences;
159 }
160
161 /**
162 * Search a type collection for duplicate typenames
163 * @param prog the program to search
164 * @param type_collection the type collection to search
165 * @param t the type to test for collisions
166 * @return the number of certain typename collisions
167 */
168 template <class T>
169 int collection_typename_count(const t_program* prog, const T type_collection, const t_type* t) const {
170 int occurrences = 0;
171 for (auto it = type_collection.cbegin(); it != type_collection.cend(); ++it)
172 if (t != *it && 0 == t->get_name().compare((*it)->get_name()) && is_common_namespace(prog, t))
173 ++occurrences;
174 return occurrences;
175 }
176
177 /**
178 * Determine whether identical typenames will collide based on namespaces.
179 *
180 * Because we do not know which languages the user will generate code for,
181 * collisions within programs (IDL files) having namespace declarations can be
182 * difficult to determine. Only guaranteed collisions return true (cause an error).
183 * Possible collisions involving explicit namespace declarations produce a warning.
184 * Other possible collisions go unreported.
185 * @param prog the program containing the preexisting typename
186 * @param t the type containing the typename match
187 * @return true if a collision within namespaces is found, otherwise false
188 */
189 bool is_common_namespace(const t_program* prog, const t_type* t) const {
190 // Case 1: Typenames are in the same program [collision]
191 if (prog == t->get_program()) {
192 pwarning(1,
193 "Duplicate typename %s found in %s",
194 t->get_name().c_str(),
195 t->get_program()->get_name().c_str());
196 return true;
197 }
198
199 // Case 2: Both programs have identical namespace scope/name declarations [collision]
200 bool match = true;
201 for (auto it = prog->namespaces_.cbegin();
202 it != prog->namespaces_.cend();
203 ++it) {
204 if (0 == it->second.compare(t->get_program()->get_namespace(it->first))) {
205 pwarning(1,
206 "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
207 t->get_name().c_str(),
208 t->get_program()->get_name().c_str(),
209 it->first.c_str(),
210 it->second.c_str(),
211 prog->get_name().c_str(),
212 it->first.c_str(),
213 it->second.c_str());
214 } else {
215 match = false;
216 }
217 }
218 for (auto it = t->get_program()->namespaces_.cbegin();
219 it != t->get_program()->namespaces_.cend();
220 ++it) {
221 if (0 == it->second.compare(prog->get_namespace(it->first))) {
222 pwarning(1,
223 "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
224 t->get_name().c_str(),
225 t->get_program()->get_name().c_str(),
226 it->first.c_str(),
227 it->second.c_str(),
228 prog->get_name().c_str(),
229 it->first.c_str(),
230 it->second.c_str());
231 } else {
232 match = false;
233 }
234 }
235 if (0 == prog->namespaces_.size() && 0 == t->get_program()->namespaces_.size()) {
236 pwarning(1,
237 "Duplicate typename %s found in %s and %s",
238 t->get_name().c_str(),
239 t->get_program()->get_name().c_str(),
240 prog->get_name().c_str());
241 }
242 return match;
243 }
244
245 // Scoping and namespacing
246 void set_namespace(std::string name) { namespace_ = name; }
247
248 // Scope accessor
249 t_scope* scope() { return scope_; }
250
251 const t_scope* scope() const { return scope_; }
252
253 // Includes
254
255 void add_include(t_program* program) {
256 includes_.push_back(program);
257 }
258
259 void add_include(std::string path, std::string include_site) {
260 t_program* program = new t_program(path);
261
262 // include prefix for this program is the site at which it was included
263 // (minus the filename)
264 std::string include_prefix;
265 std::string::size_type last_slash = std::string::npos;
266 if ((last_slash = include_site.rfind("/")) != std::string::npos) {
267 include_prefix = include_site.substr(0, last_slash);
268 }
269
270 program->set_include_prefix(include_prefix);
271 includes_.push_back(program);
272 }
273
274 void set_include_prefix(std::string include_prefix) {
275 include_prefix_ = include_prefix;
276
277 // this is intended to be a directory; add a trailing slash if necessary
278 std::string::size_type len = include_prefix_.size();
279 if (len > 0 && include_prefix_[len - 1] != '/') {
280 include_prefix_ += '/';
281 }
282 }
283
284 // Language neutral namespace / packaging
285 void set_namespace(std::string language, std::string name_space) {
286 if (language != "*") {
287 size_t sub_index = language.find('.');
288 std::string base_language = language.substr(0, sub_index);
289
290 if (base_language == "smalltalk") {
291 pwarning(1, "Namespace 'smalltalk' is deprecated. Use 'st' instead");
292 base_language = "st";
293 }
294 else if ((base_language == "csharp") || (base_language == "netcore")) {
295 pwarning(1, "The '%s' target is deprecated. Consider moving to 'netstd' instead.", base_language.c_str());
296 // warn only, don't change base_language
297 }
298
299 t_generator_registry::gen_map_t my_copy = t_generator_registry::get_generator_map();
300
301 t_generator_registry::gen_map_t::iterator it;
302 it = my_copy.find(base_language);
303
304 if (it == my_copy.end()) {
305 std::string warning = "No generator named '" + base_language + "' could be found!";
306 pwarning(1, warning.c_str());
307 } else {
308 if (sub_index != std::string::npos) {
309 std::string sub_namespace = language.substr(sub_index + 1);
310 if (!it->second->is_valid_namespace(sub_namespace)) {
311 std::string warning = base_language + " generator does not accept '" + sub_namespace
312 + "' as sub-namespace!";
313 pwarning(1, warning.c_str());
314 }
315 }
316 }
317 }
318
319 namespaces_[language] = name_space;
320 }
321
322 std::string get_namespace(std::string language) const {
323 std::map<std::string, std::string>::const_iterator iter;
324 if ((iter = namespaces_.find(language)) != namespaces_.end()
325 || (iter = namespaces_.find("*")) != namespaces_.end()) {
326 return iter->second;
327 }
328 return std::string();
329 }
330
331 const std::map<std::string, std::string>& get_all_namespaces() const {
332 return namespaces_;
333 }
334
335 void set_namespace_annotations(std::string language, std::map<std::string, std::string> annotations) {
336 namespace_annotations_[language] = annotations;
337 }
338
339 const std::map<std::string, std::string>& get_namespace_annotations(const std::string& language) const {
340 auto it = namespace_annotations_.find(language);
341 if (namespace_annotations_.end() != it) {
342 return it->second;
343 }
344 static const std::map<std::string, std::string> emptyMap;
345 return emptyMap;
346 }
347
348 std::map<std::string, std::string>& get_namespace_annotations(const std::string& language) {
349 return namespace_annotations_[language];
350 }
351
352 // Language specific namespace / packaging
353
354 void add_cpp_include(std::string path) { cpp_includes_.push_back(path); }
355
356 const std::vector<std::string>& get_cpp_includes() const { return cpp_includes_; }
357
358 void add_c_include(std::string path) { c_includes_.push_back(path); }
359
360 const std::vector<std::string>& get_c_includes() const { return c_includes_; }
361
362 void set_recursive(const bool recursive) { recursive_ = recursive; }
363
364 bool get_recursive() const { return recursive_; }
365
366 private:
367 // File path
368 std::string path_;
369
370 // Name
371 std::string name_;
372
373 // Output directory
374 std::string out_path_;
375
376 // Output directory is absolute location for generated source (no gen-*)
377 bool out_path_is_absolute_;
378
379 // Namespace
380 std::string namespace_;
381
382 // Included programs
383 std::vector<t_program*> includes_;
384
385 // Include prefix for this program, if any
386 std::string include_prefix_;
387
388 // Identifier lookup scope
389 t_scope* scope_;
390
391 // Components to generate code for
392 std::vector<t_typedef*> typedefs_;
393 std::vector<t_enum*> enums_;
394 std::vector<t_const*> consts_;
395 std::vector<t_struct*> objects_;
396 std::vector<t_struct*> structs_;
397 std::vector<t_struct*> xceptions_;
398 std::vector<t_service*> services_;
399
400 // Dynamic namespaces
401 std::map<std::string, std::string> namespaces_;
402
403 // Annotations for dynamic namespaces
404 std::map<std::string, std::map<std::string, std::string> > namespace_annotations_;
405
406 // C++ extra includes
407 std::vector<std::string> cpp_includes_;
408
409 // C extra includes
410 std::vector<std::string> c_includes_;
411
412 // Recursive code generation
413 bool recursive_;
414 };
415
416 #endif