]>
git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/parse/t_program.h
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
28 #include "thrift/main.h"
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"
45 * Top level class representing an entire thrift program. A program consists
46 * fundamentally of the following:
55 * The program module also contains the definitions of the base types.
58 class t_program
: public t_doc
{
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) {}
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();
68 ~t_program() override
{
76 const std::string
& get_path() const { return path_
; }
78 // Output path accessor
79 const std::string
& get_out_path() const { return out_path_
; }
81 // Create gen-* dir accessor
82 bool is_out_path_absolute() const { return out_path_is_absolute_
; }
85 const std::string
& get_name() const { return name_
; }
88 const std::string
& get_namespace() const { return namespace_
; }
90 // Include prefix accessor
91 const std::string
& get_include_prefix() const { return include_prefix_
; }
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_
; }
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
);
111 void add_xception(t_struct
* tx
) {
112 objects_
.push_back(tx
);
113 xceptions_
.push_back(tx
);
115 void add_service(t_service
* ts
) { services_
.push_back(ts
); }
117 // Programs to include
118 std::vector
<t_program
*>& get_includes() { return includes_
; }
120 const std::vector
<t_program
*>& get_includes() const { return includes_
; }
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('/');
132 // Typename collision detection
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
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
);
143 return 0 == occurrences
;
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
152 int program_typename_count(const t_program
* prog
, const t_type
* t
) const {
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
);
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
169 int collection_typename_count(const t_program
* prog
, const T type_collection
, const t_type
* t
) const {
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
))
178 * Determine whether identical typenames will collide based on namespaces.
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
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()) {
193 "Duplicate typename %s found in %s",
194 t
->get_name().c_str(),
195 t
->get_program()->get_name().c_str());
199 // Case 2: Both programs have identical namespace scope/name declarations [collision]
201 for (auto it
= prog
->namespaces_
.cbegin();
202 it
!= prog
->namespaces_
.cend();
204 if (0 == it
->second
.compare(t
->get_program()->get_namespace(it
->first
))) {
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(),
211 prog
->get_name().c_str(),
218 for (auto it
= t
->get_program()->namespaces_
.cbegin();
219 it
!= t
->get_program()->namespaces_
.cend();
221 if (0 == it
->second
.compare(prog
->get_namespace(it
->first
))) {
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(),
228 prog
->get_name().c_str(),
235 if (0 == prog
->namespaces_
.size() && 0 == t
->get_program()->namespaces_
.size()) {
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());
245 // Scoping and namespacing
246 void set_namespace(std::string name
) { namespace_
= name
; }
249 t_scope
* scope() { return scope_
; }
251 const t_scope
* scope() const { return scope_
; }
255 void add_include(t_program
* program
) {
256 includes_
.push_back(program
);
259 void add_include(std::string path
, std::string include_site
) {
260 t_program
* program
= new t_program(path
);
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
);
270 program
->set_include_prefix(include_prefix
);
271 includes_
.push_back(program
);
274 void set_include_prefix(std::string include_prefix
) {
275 include_prefix_
= include_prefix
;
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_
+= '/';
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
);
290 if (base_language
== "smalltalk") {
291 pwarning(1, "Namespace 'smalltalk' is deprecated. Use 'st' instead");
292 base_language
= "st";
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
299 t_generator_registry::gen_map_t my_copy
= t_generator_registry::get_generator_map();
301 t_generator_registry::gen_map_t::iterator it
;
302 it
= my_copy
.find(base_language
);
304 if (it
== my_copy
.end()) {
305 std::string warning
= "No generator named '" + base_language
+ "' could be found!";
306 pwarning(1, warning
.c_str());
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());
319 namespaces_
[language
] = name_space
;
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()) {
328 return std::string();
331 const std::map
<std::string
, std::string
>& get_all_namespaces() const {
335 void set_namespace_annotations(std::string language
, std::map
<std::string
, std::string
> annotations
) {
336 namespace_annotations_
[language
] = annotations
;
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
) {
344 static const std::map
<std::string
, std::string
> emptyMap
;
348 std::map
<std::string
, std::string
>& get_namespace_annotations(const std::string
& language
) {
349 return namespace_annotations_
[language
];
352 // Language specific namespace / packaging
354 void add_cpp_include(std::string path
) { cpp_includes_
.push_back(path
); }
356 const std::vector
<std::string
>& get_cpp_includes() const { return cpp_includes_
; }
358 void add_c_include(std::string path
) { c_includes_
.push_back(path
); }
360 const std::vector
<std::string
>& get_c_includes() const { return c_includes_
; }
362 void set_recursive(const bool recursive
) { recursive_
= recursive
; }
364 bool get_recursive() const { return recursive_
; }
374 std::string out_path_
;
376 // Output directory is absolute location for generated source (no gen-*)
377 bool out_path_is_absolute_
;
380 std::string namespace_
;
383 std::vector
<t_program
*> includes_
;
385 // Include prefix for this program, if any
386 std::string include_prefix_
;
388 // Identifier lookup scope
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_
;
400 // Dynamic namespaces
401 std::map
<std::string
, std::string
> namespaces_
;
403 // Annotations for dynamic namespaces
404 std::map
<std::string
, std::map
<std::string
, std::string
> > namespace_annotations_
;
406 // C++ extra includes
407 std::vector
<std::string
> cpp_includes_
;
410 std::vector
<std::string
> c_includes_
;
412 // Recursive code generation