v8toolkit  0.0.1
Utility library for embedding V8 Javascript engine in a c++ program
helper_functions.cpp
Go to the documentation of this file.
1 
2 
3 #include "helper_functions.h"
4 
5 #include <iostream>
6 #include <fstream>
7 #include <fmt/ostream.h>
8 
9 #include <clang/AST/CXXInheritance.h>
10 
11 #include "wrapped_class.h"
12 
13 
14 string make_macro_safe_comma(string const & input) {
15  return std::regex_replace(input, std::regex("\\s*,\\s*"), " V8TOOLKIT_COMMA ");
16 }
17 
18 // Gets the "most basic" type in a type. Strips off ref, pointer, CV
19 // then calls out to get how to include that most basic type definition
20 // and puts it in wrapped_class.include_files
22  // don't capture qualtype by ref since it is changed in this function
23  QualType qual_type) {
24 
25  cerr << fmt::format("In update_wrapped_class_for_type {} in wrapped class {}", qual_type.getAsString(), wrapped_class.class_name) << endl;
26 
27  if (print_logging) cerr << "Went from " << qual_type.getAsString();
28  qual_type = qual_type.getLocalUnqualifiedType();
29 
30 
31  // remove pointers
32  while(!qual_type->getPointeeType().isNull()) {
33  qual_type = qual_type->getPointeeType();
34  }
35  qual_type = qual_type.getLocalUnqualifiedType();
36 
37  if (print_logging) cerr << " to " << qual_type.getAsString() << endl;
38  auto base_type_record_decl = qual_type->getAsCXXRecordDecl();
39 
40 
41 
42  if (auto function_type = dyn_cast<FunctionType>(&*qual_type)) {
43  cerr << "IS A FUNCTION TYPE!!!!" << endl;
44 
45  // it feels strange, but the type int(bool) from std::function<int(bool)> is a FunctionProtoType
46  if (auto function_prototype = dyn_cast<FunctionProtoType>(function_type)) {
47  cerr << "IS A FUNCTION PROTOTYPE" << endl;
48 
49  cerr << "Recursing on return type" << endl;
50  update_wrapped_class_for_type(wrapped_class, function_prototype->getReturnType());
51 
52  for ( auto param : function_prototype->param_types()) {
53 
54  cerr << "Recursing on param type" << endl;
55  update_wrapped_class_for_type(wrapped_class, param);
56  }
57  } else {
58  cerr << "IS NOT A FUNCTION PROTOTYPE" << endl;
59  }
60 
61  } else {
62  cerr << "is not a FUNCTION TYPE" << endl;
63  }
64 
65 
66  // primitive types don't have record decls
67  if (base_type_record_decl == nullptr) {
68  return;
69  }
70 
71  auto actual_include_string = get_include_for_type_decl(wrapped_class.compiler_instance, base_type_record_decl);
72 
73  if (print_logging) cerr << &wrapped_class << "Got include string for " << qual_type.getAsString() << ": " << actual_include_string << endl;
74 
75  // if there's no wrapped type, it may be something like a std::function or STL container -- those are ok to not be wrapped
76  if (has_wrapped_class(base_type_record_decl)) {
77  auto & used_wrapped_class = WrappedClass::get_or_insert_wrapped_class(base_type_record_decl, wrapped_class.compiler_instance, FOUND_UNSPECIFIED);
78  wrapped_class.used_classes.insert(&used_wrapped_class);
79  }
80 
81 
82 
83  wrapped_class.include_files.insert(actual_include_string);
84  cerr << fmt::format("{} now has {} include files having added {}", wrapped_class.name_alias, wrapped_class.include_files.size(), actual_include_string) << endl;
85 
86 
87  if (dyn_cast<ClassTemplateSpecializationDecl>(base_type_record_decl)) {
88  if (print_logging) cerr << "##!#!#!#!# Oh shit, it's a template type " << qual_type.getAsString() << endl;
89 
90  auto template_specialization_decl = dyn_cast<ClassTemplateSpecializationDecl>(base_type_record_decl);
91 
92  // go through the template args
93  auto & template_arg_list = template_specialization_decl->getTemplateArgs();
94  for (decltype(template_arg_list.size()) i = 0; i < template_arg_list.size(); i++) {
95  auto & arg = template_arg_list[i];
96 
97  // this code only cares about types, so skip non-type template arguments
98  if (arg.getKind() != clang::TemplateArgument::Type) {
99  continue;
100  }
101  auto template_arg_qual_type = arg.getAsType();
102  if (template_arg_qual_type.isNull()) {
103  if (print_logging) cerr << "qual type is null" << endl;
104  continue;
105  }
106  if (print_logging) cerr << "Recursing on templated type " << template_arg_qual_type.getAsString() << endl;
107  update_wrapped_class_for_type(wrapped_class, template_arg_qual_type);
108  }
109  } else {
110  if (print_logging) cerr << "Not a template specializaiton type " << qual_type.getAsString() << endl;
111  }
112 }
113 
114 
115 
116 
117 
118 EXPORT_TYPE get_export_type(const NamedDecl * decl, EXPORT_TYPE previous) {
119  auto &attrs = decl->getAttrs();
120  EXPORT_TYPE export_type = previous;
121 
122  auto name = decl->getNameAsString();
123 
124  bool found_export_specifier = false;
125 
126  for (auto attr : attrs) {
127  if (dyn_cast<AnnotateAttr>(attr)) {
128  auto attribute_attr = dyn_cast<AnnotateAttr>(attr);
129  auto annotation_string = attribute_attr->getAnnotation().str();
130 
131  if (annotation_string == V8TOOLKIT_ALL_STRING) {
132  if (found_export_specifier) { data_error(fmt::format("Found more than one export specifier on {}", name));}
133 
134  export_type = EXPORT_ALL;
135  found_export_specifier = true;
136  } else if (annotation_string == "v8toolkit_generate_bindings_some") {
137  if (found_export_specifier) { data_error(fmt::format("Found more than one export specifier on {}", name));}
138  export_type = EXPORT_SOME;
139  found_export_specifier = true;
140  } else if (annotation_string == "v8toolkit_generate_bindings_except") {
141  if (found_export_specifier) { data_error(fmt::format("Found more than one export specifier on {}", name).c_str());}
142  export_type = EXPORT_EXCEPT;
143  found_export_specifier = true;
144  } else if (annotation_string == V8TOOLKIT_NONE_STRING) {
145  if (found_export_specifier) { data_error(fmt::format("Found more than one export specifier on {}", name).c_str());}
146  export_type = EXPORT_NONE; // just for completeness
147  found_export_specifier = true;
148  }
149  }
150  }
151 
152  // go through bases looking for specific ones
153  if (const CXXRecordDecl * record_decl = dyn_cast<CXXRecordDecl>(decl)) {
154  for (auto & base : record_decl->bases()) {
155  auto type = base.getType();
156  auto base_decl = type->getAsCXXRecordDecl();
157  auto base_name = get_canonical_name_for_decl(base_decl);
158 // cerr << "%^%^%^%^%^%^%^% " << get_canonical_name_for_decl(base_decl) << endl;
159  if (base_name == "class v8toolkit::WrappedClassBase") {
160  cerr << "FOUND WRAPPED CLASS BASE -- EXPORT_ALL" << endl;
161  if (found_export_specifier) { data_error(fmt::format("Found more than one export specifier on {}", name).c_str());}
162  export_type = EXPORT_ALL;
163  found_export_specifier = true;
164  }
165  }
166  }
167 
168  // printf("Returning export type: %d for %s\n", export_type, name.c_str());
169  return export_type;
170 }
171 
172 
173 
174 std::string get_canonical_name_for_decl(const TypeDecl * decl) {
175  if (decl == nullptr) {
176  llvm::report_fatal_error("null type decl to get_canonical_name_for_decl");
177  }
178  return decl->getTypeForDecl()->getCanonicalTypeInternal().getAsString();
179 }
180 
181 //
182 // std::string get_full_name_for_type(QualType qual_type) {
183 //
184 // if (auto typedef_decl = qual_type->getAs<TypedefNameDecl>()) {
185 // qual_type = typedef_decl->getUnderlyingType();
186 // }
187 // auto record_decl = qual_type->getAsCXXRecordDecl();
188 // if (record_decl == nullptr) {
189 // std::cerr << fmt::format("Couldn't get record decl for {}", qual_type.getAsString()) << std::endl;
190 // assert(record_decl != nullptr);
191 // }
192 //
193 // return get_canonical_name_for_decl(record_decl);
194 // }
195 
196 
197 
198 
199 // list of data (source code being processed) errors occuring during the run. Clang API errors are still immediate fails with
200 // llvm::report_fatal_error
201 vector<string> data_errors;
202 void data_error(const string & error) {
203  cerr << "DATA ERROR: " << error << endl;
204  data_errors.push_back(error);
205 }
206 
207 vector<string> data_warnings;
208 void data_warning(const string & warning) {
209  cerr << "DATA WARNING: " << warning << endl;
210  data_warnings.push_back(warning);
211 }
212 
213 QualType get_plain_type(QualType qual_type) {
214  auto type = qual_type.getNonReferenceType();//.getUnqualifiedType();
215  while(!type->getPointeeType().isNull()) {
216  type = type->getPointeeType();//.getUnqualifiedType();
217  }
218  return type;
219 }
220 
221 
222 
224 
225  // current file number for bindings file so it can be broken down into multiple files
226  int file_count = 1;
227 
228  // start at one so they are never considered "empty"
229  int declaration_count_this_file = 1;
230 
231  vector<WrappedClass*> classes_for_this_file;
232 
233  set<WrappedClass *> already_wrapped_classes;
234 
235  vector<vector<WrappedClass *>> classes_per_file;
236 
237  ofstream js_stub;
238 
239 
240  cerr << fmt::format("About to start writing out wrapped classes with {} potential classes", WrappedClass::wrapped_classes.size()) << endl;
241 
242 
243  // go through all the classes until a full pass has been made with nothing new to be written out
244  bool found_match = true;
245  while (found_match) {
246  found_match = false;
247 
248  // go through the list to see if there is anything left to write out
249  for (auto wrapped_class : WrappedClass::wrapped_classes) {
250 
251  if (!wrapped_class->should_be_wrapped()) {
252  continue;
253  }
254 
255 
256  cerr << fmt::format("considering dumping class: {}", wrapped_class->class_name) << endl;
257 
258  // if it has unmet dependencies or has already been mapped, skip it
259  if (!wrapped_class->ready_for_wrapping(already_wrapped_classes)) {
260  std::cerr << fmt::format("Skipping {}", wrapped_class->class_name) << std::endl;
261  continue;
262  }
263  already_wrapped_classes.insert(wrapped_class);
264  found_match = true;
265 
266  std::cerr << fmt::format("writing class {} to file with declaration_count = {}", wrapped_class->name_alias, wrapped_class->declaration_count) << std::endl;
267 
268  // if there's room in the current file, add this class
269  auto space_available = declaration_count_this_file == 0 ||
270  declaration_count_this_file + wrapped_class->declaration_count <
272 
273  if (!space_available) {
274 
275 
276  std::cerr << fmt::format("Out of space in file, rotating") << std::endl;
277  classes_per_file.emplace_back(classes_for_this_file);
278 
279  // reset for next file
280  classes_for_this_file.clear();
281  declaration_count_this_file = 0;
282  file_count++;
283  }
284 
285  classes_for_this_file.push_back(wrapped_class);
286  wrapped_class->dumped = true;
287  declaration_count_this_file += wrapped_class->declaration_count;
288  }
289  }
290 
291 
292 
293 
294  // if the last file set isn't empty, add that, too
295  if (!classes_for_this_file.empty()) {
296  classes_per_file.emplace_back(classes_for_this_file);
297  }
298 
299  if (already_wrapped_classes.size() != WrappedClass::wrapped_classes.size()) {
300  cerr << fmt::format("Could not wrap all classes - wrapped {} out of {}",
301  already_wrapped_classes.size(), WrappedClass::wrapped_classes.size()) << endl;
302  }
303 
304  int total_file_count = classes_per_file.size();
305  for (int i = 0; i < total_file_count; i++) {
306  write_classes(i + 1, classes_per_file[i], i == total_file_count - 1);
307  }
308 
309 
310 // if (generate_v8classwrapper_sfinae) {
311 // string sfinae_filename = fmt::format("v8toolkit_generated_v8classwrapper_sfinae.h", file_count);
312 // ofstream sfinae_file;
313 //
314 // sfinae_file.open(sfinae_filename, ios::out);
315 // if (!sfinae_file) {
316 // llvm::report_fatal_error(fmt::format( "Couldn't open {}", sfinae_filename).c_str());
317 // }
318 //
319 // sfinae_file << "#pragma once\n\n";
320 //
321 // sfinae_file << get_sfinae_matching_wrapped_classes(WrappedClass::wrapped_classes) << std::endl;
322 // sfinae_file.close();
323 // }
324 
325  cerr << "Classes returned from matchers: " << matched_classes_returned << endl;
326 
327 
328  cerr << "Classes used that were not wrapped:" << endl;
329  for ( auto & wrapped_class : WrappedClass::wrapped_classes) {
330  if (!wrapped_class->dumped) { continue; }
331  for (auto used_class : wrapped_class->used_classes) {
332  if (!used_class->dumped) {
333  cerr << fmt::format("{} uses unwrapped type: {}", wrapped_class->name_alias, used_class->name_alias) << endl;
334  }
335  }
336 
337  }
338 
339 
340 
341 }
342 
343 void generate_javascript_stub(std::string const & filename) {
344  ofstream js_stub;
345  // This filename shouldn't be hard coded - especially not to this value
346  js_stub.open(filename, ios::out);
347  if (!js_stub) {
348  throw std::exception();
349  }
350 
351  // write hard-coded text to top of apb api file
352  js_stub << js_api_header << std::endl;
353 
354  for (auto * wrapped_class : WrappedClass::wrapped_classes) {
355  // bidirectional types don't have
356  if (wrapped_class->should_be_wrapped() && !wrapped_class->bidirectional) {
357  js_stub << wrapped_class->generate_js_stub();
358  }
359  }
360  js_stub.close();
361 
362 
363 
364 }
365 
366 void generate_bidirectional_classes(CompilerInstance & compiler_instance) {
367  cerr << "Generating bidirectional classes..." << endl;
368 
369  // use this style loop because entries will be added inside the loop
370  for (auto wrapped_class_iterator = WrappedClass::wrapped_classes.begin();
371  wrapped_class_iterator != WrappedClass::wrapped_classes.end();
372  wrapped_class_iterator++) {
373  auto wrapped_class = *wrapped_class_iterator;
374 
375  // this code wants the actual bidirecitonal class, not the base class it wraps (e.g. JSFoo, not Foo)
376  if (!wrapped_class->bidirectional) {
377  continue;
378  }
379 
380 
381  cerr << fmt::format("Building bidirectional class {}", wrapped_class->name_alias) << endl;
382 
383  assert(wrapped_class->base_types.size() == 1);
384  auto base_type = *wrapped_class->base_types.begin();
385 
386  // create the file for the include, stripping off any "" or <> (should only be "'s)
387  ofstream bidirectional_file(regex_replace(wrapped_class->my_include, std::regex("[<>\"]"), ""));
388 
389  bidirectional_file << endl << "#pragma once\n\n";
390 
391 
392  // need to include all the includes from the parent types because the implementation of this bidirectional
393  // type may need the types for things the parent type .h files don't need (like unique_ptr contained types)
394  for (auto & include : wrapped_class->get_base_type_includes()) {
395  if (include == "") {
396  continue;
397  }
398  std::cerr << fmt::format("for bidirectional {}, adding base type include {}", wrapped_class->name_alias, include) << std::endl;
399  bidirectional_file << "#include " << include << "\n";
400  }
401 
402  // std::cerr << fmt::format("done adding base type includes now adding wrapped_class include files") << std::endl;
403  for (auto & include : wrapped_class->include_files) {
404  if (include == "") {
405  continue;
406  }
407  bidirectional_file << "#include " << include << "\n";
408  }
409  bidirectional_file << endl; // blank line between includes and class definition
410 
411  std::cerr << fmt::format("done with includes, building class and constructor") << std::endl;
412  bidirectional_file << fmt::format(
413  "class JS{} : public {}, public v8toolkit::JSWrapper<{}> {{\npublic:", // {{ is escaped {
414  base_type->name_alias, base_type->name_alias, base_type->name_alias) << endl;
415 
416  std::cerr << fmt::format("cc1") << std::endl;
417  bidirectional_file
418  << fmt::format(" JS{}(v8::Local<v8::Context> context, v8::Local<v8::Object> object,",
419  base_type->name_alias) << endl;
420  std::cerr << fmt::format("cc2") << std::endl;
421  bidirectional_file << fmt::format(" v8::Local<v8::FunctionTemplate> created_by") << endl;
422  std::cerr << fmt::format("cc3") << std::endl;
423  std::cerr << fmt::format("dealing with bidirectional constructor at {} for class {}", (void*)base_type->bidirectional_constructor,base_type->name_alias) << std::endl;
424  if (base_type->bidirectional_constructor == nullptr) {
425  llvm::report_fatal_error(fmt::format("bidirectional constructor: {} for class {}",
426  (void*)base_type->bidirectional_constructor,
427  base_type->name_alias));
428  }
429  ClassFunction bidirectional_constructor(*base_type, base_type->bidirectional_constructor);
430  std::cerr << fmt::format("cc3.1") << std::endl;
431  int param_position = 1;
432  for (auto & parameter : bidirectional_constructor.parameters) {
433  std::cerr << fmt::format("cc3.in_loop top") << std::endl;
434  bidirectional_file << fmt::format(", {} var{}", parameter.type.name, param_position++);
435  std::cerr << fmt::format("cc3.in_loop bottom") << std::endl;
436  }
437 
438 
439  std::cerr << fmt::format("cc4") << std::endl;
440  bidirectional_file << fmt::format(") :") << endl;
441 
442  // auto variable_names = generate_variable_names(construtor_parameter_count);
443  auto variable_names = generate_variable_names(get_method_param_qual_types(compiler_instance, base_type->bidirectional_constructor), true);
444  std::cerr << fmt::format("cc5") << std::endl;
445  bidirectional_file << fmt::format(" {}({}),", base_type->name_alias, join(variable_names)) << endl;
446  bidirectional_file << fmt::format(" v8toolkit::JSWrapper<{}>(context, object, created_by) {{}}", base_type->name_alias) << endl; // {{}} is escaped {}
447  bidirectional_file << endl;
448 
449  cerr << fmt::format("bidirectional class has {} methods, looking for virtual ones", base_type->get_member_functions().size()) << endl;
450 
451 
452 
453 
454  auto * current_inheritance_class = base_type;
455  set<string> js_access_virtual_methods_added;
456 
457  cerr << fmt::format("building virtual method list for {}", wrapped_class->name_alias);
458  while(current_inheritance_class) {
459  cerr << fmt::format(" ** Inheritance hierarchy class: {} with {} base types", current_inheritance_class->name_alias, current_inheritance_class->base_types.size()) << endl;
460 
461  for (auto & method : current_inheritance_class->get_member_functions()) {
462  if (!method->is_virtual) {
463  continue;
464  }
465  auto added_method = js_access_virtual_methods_added.find(method->get_signature_string());
466 
467  // check if it's already been added at a more derived type
468  if (added_method != js_access_virtual_methods_added.end()) {
469  continue;
470  }
471 
472  js_access_virtual_methods_added.insert(method->get_signature_string());
473 
474 
475  auto bidirectional_virtual_method = method->method_decl;
476  auto num_params = bidirectional_virtual_method->getNumParams();
477 // printf("Dealing with %s\n", method->getQualifiedNameAsString().c_str());
478 
479 
480  stringstream js_access_virtual_method_string;
481 
482  //std::cerr << fmt::format("10") << std::endl;
483  js_access_virtual_method_string << " JS_ACCESS_" << num_params
484  << (bidirectional_virtual_method->isConst() ? "_CONST(" : "(");
485 
486  js_access_virtual_method_string << make_macro_safe_comma(method->return_type.name) << ", ";
487 
488  //std::cerr << fmt::format("11 - num_params: {}", num_params) << std::endl;
489  js_access_virtual_method_string << bidirectional_virtual_method->getName().str();
490 
491  if (num_params > 0) {
492  //std::cerr << fmt::format("12") << std::endl;
493  auto types = get_method_param_qual_types(wrapped_class->compiler_instance,
494  bidirectional_virtual_method);
495  vector<string> type_names;
496  for (auto &type : types) {
497  type_names.push_back(make_macro_safe_comma(type.getAsString()));
498  }
499 
500  js_access_virtual_method_string << join(type_names, ", ", true);
501  }
502 
503 
504  //std::cerr << fmt::format("13") << std::endl;
505  js_access_virtual_method_string << ");\n";
506 
507 
508  if (js_access_virtual_methods_added.count(js_access_virtual_method_string.str())) {
509  continue;
510  }
511  js_access_virtual_methods_added.insert(js_access_virtual_method_string.str());
512  bidirectional_file << js_access_virtual_method_string.str();
513 
514  }
515 
516 
517 
518  current_inheritance_class = *current_inheritance_class->base_types.begin();
519  }
520 
521 // // go through all the virtual functions in the base class of the bidirectional type
522 // CXXFinalOverriderMap override_map;
523 // base_type->decl->getFinalOverriders(override_map);
524 // std::cerr << fmt::format("6") << std::endl;
525 //
526 // // store which virtual methods have already been added so they aren't added multiple times
527 // set<string> js_access_virtual_methods_added;
528 // map<CXXRecordDecl const *, set<CXXMethodDecl const *>> class_virtuals;
529 //
530 // for(auto & overrider_pair : override_map) {
531 //
532 // CXXMethodDecl const *bidirectional_virtual_method = overrider_pair.first;
533 //
534 // // skip virtual destructors
535 // if (dyn_cast<CXXDestructorDecl>(bidirectional_virtual_method)) {
536 // continue;
537 // }
538 //
539 // std::cerr << fmt::format(
540 // "Looking at overrider pair for virtual method {} cxxmethoddecl {} parent class decl: {}",
541 // bidirectional_virtual_method->getNameAsString(), (void *) bidirectional_virtual_method,
542 // bidirectional_virtual_method->getParent()->getNameAsString()) << std::endl;
543 // std::cerr << fmt::format("7") << std::endl;
544 // if (!bidirectional_virtual_method->isVirtual()) {
545 // llvm::report_fatal_error("Assuming this must be virtual");
546 // }
547 // class_virtuals[bidirectional_virtual_method->getParent()].insert(bidirectional_virtual_method);
548 // }
549 //
550 // // now go through the inheritance chain and only populate with the first one found
551 // map<string, CXXMethodDecl const *> final_virtuals; // map string signature to actual decl
552 // auto current_inheritance_class = wrapped_class;
553 //
554 // while(current_inheritance_class) {
555 // auto find_result = class_virtuals.find(current_inheritance_class->decl);
556 // if (find_result == class_virtuals.end()) {
557 // continue;
558 // }
559 //
560 // for (auto virtual_decl : find_result->second) {
561 // string virtual_decl_signature =
562 // if (final_virtuals.find())
563 // }
564 // }
565 
566 //
567 // std::cerr << fmt::format("8") << std::endl;
568 // // skip pure virtual functions
569 // if (bidirectional_virtual_method->isPure()) {
570 // continue;
571 // }
572  bidirectional_file << endl << "};" << endl << endl;
573 
574 
575 
576  bidirectional_file.close();
577 
578  }
579 }
580 //
581 //// converts from c++ type to javascript type
582 //string convert_type_to_jsdoc(std::string const & type_name_input) {
583 // string type_name = type_name_input;
584 // std::smatch matches;
585 // std::cerr << fmt::format("converting {}...", type_name) << std::endl;
586 //
587 // // remove any leading struct/class text
588 // type_name = regex_replace(type_name, std::regex("^(struct|class) "), "");
589 //
590 //
591 //
592 //
593 //// // things like: change vector<int> to Array.[Number]
594 //// for (auto &pair : cpp_to_js_type_conversions) {
595 ////
596 //// if (regex_match(type_name, matches, std::regex(pair.first))) {
597 //// std::cerr << fmt::format("matched {}, converting to {}", pair.first, pair.second) << std::endl;
598 ////
599 //// string replacement_type = pair.second; // need a temp because the regex matches point into the current this->type
600 ////
601 //// // go through each capturing match and...
602 //// for (size_t i = 1; i < matches.size(); i++) {
603 ////// // recursively convert the matched type
604 //// string converted_captured_type_name = convert_type_to_jsdoc(matches[i].str());
605 ////
606 //// // look for $1, $2, etc in replacement and substitute in the matching position
607 //// replacement_type = std::regex_replace(replacement_type, std::regex(fmt::format("\\${}", i)),
608 //// converted_captured_type_name);
609 //// }
610 //// type_name = replacement_type;
611 //// std::cerr << fmt::format("... final conversion to: {}", replacement_type) << std::endl;
612 //// break;
613 //// }
614 //// }
615 //
616 // std::cerr << fmt::format("returning jsdoc converted type: {}", type_name) << std::endl;
617 // return type_name;
618 //}
619 //
620 //
621 
622 
623 
624 
625 
626 
627 #if 0
628 //ifdef TEMPLATE_INFO_ONLY
629 {
630  cerr << fmt::format("Class template instantiations") << endl;
631  vector<pair<string, int>> insts;
632  for (auto & class_template : class_templates) {
633  insts.push_back({class_template->name, class_template->instantiations});
634  }
635  std::sort(insts.begin(), insts.end(), [](auto & a, auto & b){
636  return a.second < b.second;
637  });
638  int skipped = 0;
639  int total = 0;
640  cerr << endl << fmt::format("Class templates with more than {} or more instantiations:", TEMPLATED_CLASS_PRINT_THRESHOLD) << endl;
641  for (auto & pair : insts) {
642  total += pair.second;
643  if (pair.second < TEMPLATED_CLASS_PRINT_THRESHOLD) {
644  skipped++;
645  continue;
646  }
647  cerr << pair.first << ": " << pair.second << endl;;
648  }
649  cerr << endl;
650  cerr << "Skipped " << skipped << " entries because they had fewer than " << TEMPLATED_CLASS_PRINT_THRESHOLD << " instantiations" << endl;
651  cerr << "Total of " << total << " instantiations" << endl;
652  skipped = 0;
653  total = 0;
654  insts.clear();
655  for (auto & function_template : function_templates) {
656  insts.push_back({function_template->name, function_template->instantiations});
657  }
658  std::sort(insts.begin(), insts.end(), [](auto & a, auto & b){
659  return a.second < b.second;
660  });
661  cerr << endl << fmt::format("Function templates with more than {} or more instantiations:", TEMPLATED_FUNCTION_PRINT_THRESHOLD) << endl;
662  for (auto & pair : insts) {
663  total += pair.second;
664  if (pair.second < TEMPLATED_FUNCTION_PRINT_THRESHOLD) {
665  skipped++;
666  continue;
667  }
668  cerr << pair.first << ": " << pair.second << endl;;
669  }
670 
671 
672  cerr << endl;
673  cerr << "Skipped " << skipped << " entries because they had fewer than " << TEMPLATED_FUNCTION_PRINT_THRESHOLD << " instantiations" << endl;
674  cerr << "Total of " << total << " instantiations" << endl;
675  return;
676  }
677 #endif
int matched_classes_returned
set< WrappedClass * > used_classes
Definition: wrapped_class.h:78
#define V8TOOLKIT_ALL_STRING
Definition: class_parser.h:18
static WrappedClass & get_or_insert_wrapped_class(const CXXRecordDecl *decl, CompilerInstance &compiler_instance, FOUND_METHOD found_method)
string name_alias
this is the possibly shortened javascript name of the type - not necessarily valid in generated c++ ...
Definition: wrapped_class.h:46
vector< ParameterInfo > parameters
Definition: parsed_method.h:89
int print_logging
::std::string string
Definition: gtest-port.h:1097
void data_error(const string &error)
QualType get_plain_type(QualType qual_type)
void update_wrapped_class_for_type(WrappedClass &wrapped_class, QualType qual_type)
vector< QualType > get_method_param_qual_types(CompilerInstance &compiler_instance, const CXXMethodDecl *method, string const &annotation)
string make_macro_safe_comma(string const &input)
EXPORT_TYPE
static vector< WrappedClass * > wrapped_classes
Definition: wrapped_class.h:29
#define TEMPLATED_CLASS_PRINT_THRESHOLD
set< string > include_files
Definition: wrapped_class.h:48
std::string get_include_for_type_decl(CompilerInstance &compiler_instance, const TypeDecl *type_decl)
int MAX_DECLARATIONS_PER_FILE
vector< unique_ptr< FunctionTemplate > > function_templates
std::string js_api_header
vector< string > data_errors
void write_classes(int file_count, vector< WrappedClass * > &classes, bool last_one)
Definition: ast_action.cpp:14
vector< string > generate_variable_names(vector< QualType > qual_types, bool with_std_move)
vector< std::unique_ptr< ClassTemplate > > class_templates
void generate_bidirectional_classes(CompilerInstance &compiler_instance)
void data_warning(const string &warning)
EXPORT_TYPE get_export_type(const NamedDecl *decl, EXPORT_TYPE previous)
#define V8TOOLKIT_NONE_STRING
Definition: class_parser.h:17
#define TEMPLATED_FUNCTION_PRINT_THRESHOLD
void generate_javascript_stub(std::string const &filename)
string class_name
Definition: wrapped_class.h:43
vector< string > data_warnings
std::string get_canonical_name_for_decl(const TypeDecl *decl)
void generate_bindings()
std::string join(const T &source, const std::string &between=", ", bool leading_between=false)
CompilerInstance & compiler_instance
Definition: wrapped_class.h:71
bool has_wrapped_class(const CXXRecordDecl *decl)