v8toolkit  0.0.1
Utility library for embedding V8 Javascript engine in a c++ program
wrapped_class.cpp
Go to the documentation of this file.
1 
2 #include "wrapped_class.h"
3 #include "parsed_method.h"
4 #include "class_handler.h"
5 
6 // Having this too high can lead to VERY memory-intensive compilation units
7 // Single classes (+base classes) with more than this number of declarations will still be in one file.
9 
10 WrappedClass::WrappedClass(const CXXRecordDecl * decl, CompilerInstance & compiler_instance, FOUND_METHOD found_method) :
11  decl(decl),
12  class_name(get_canonical_name_for_decl(decl)),
13  name_alias(decl->getTypeForDecl()->getCanonicalTypeInternal().getAsString()),
14  compiler_instance(compiler_instance),
15  my_include(get_include_for_type_decl(compiler_instance, decl)),
16  annotations(decl),
17  found_method(found_method)
18 {
19  cerr << fmt::format("*** Creating WrappedClass for {} with found_method = {}", this->name_alias, this->found_method) << endl;
20  fprintf(stderr, "Creating WrappedClass for record decl ptr: %p\n", (void *)decl);
21  string using_name = Annotations::names_for_record_decls[decl];
22  if (!using_name.empty()) {
23  cerr << fmt::format("Setting name alias for {} to {} because of a 'using' statement", class_name, using_name) << endl;
24  name_alias = using_name;
25  }
26 
27 
28 
29  // strip off any leading "class " or "struct " off the type name
30  name_alias = regex_replace(name_alias, std::regex("^(struct|class) "), "");
31 
32 
33  cerr << "Top of WrappedClass constructor body" << endl;
34  if (class_name == "") {
35  fprintf(stderr, "%p\n", (void *)decl);
36  llvm::report_fatal_error("Empty name string for decl");
37  }
38 
39  auto pattern = this->decl->getTemplateInstantiationPattern();
40  if (pattern && pattern != this->decl) {
41  if (!pattern->isDependentType()) {
42  llvm::report_fatal_error(fmt::format("template instantiation class's pattern isn't dependent - this is not expected from my understanding: {}", class_name));
43  }
44  }
45 
46  // instantiation_pattern = pattern;
47  // annotations.merge(Annotations(instantiation_pattern));
48 
49 
50 
51  if (auto specialization = dyn_cast<ClassTemplateSpecializationDecl>(this->decl)) {
52  annotations.merge(Annotations(specialization->getSpecializedTemplate()));
53  }
54 
55 
57  this->decl->getTypeForDecl()->getCanonicalTypeInternal());
58 
59 
60  const ClassTemplateSpecializationDecl *specialization = nullptr;
61  if ((specialization = dyn_cast<ClassTemplateSpecializationDecl>(this->decl)) != nullptr) {
62  auto specialized_template = specialization->getSpecializedTemplate();
63  auto template_name = specialized_template->getNameAsString();
64  template_instantiations[template_name]++;
65  }
66 
67  cerr << "Final wrapped class annotations: " << endl;
69 
70 
71 
72  // START NEW CODE
73  bool must_have_base_type = false;
74  auto annotation_base_types_to_ignore = this->annotations.get_regex(
76  auto annotation_base_type_to_use = this->annotations.get_regex(
77  "^" V8TOOLKIT_USE_BASE_TYPE_PREFIX "(.*)$");
78  if (annotation_base_type_to_use.size() > 1) {
79  data_error(fmt::format("More than one base type specified to use for type", this->class_name));
80  }
81 
82  // if a base type to use is specified, then it must match an actual base type or error
83  if (!annotation_base_type_to_use.empty()) {
84  must_have_base_type = true;
85  }
86 
87 
88  this->include_files.insert(get_include_for_type_decl(this->compiler_instance, this->decl));
89 
90 
91  print_vector(annotation_base_types_to_ignore, "base types to ignore");
92  print_vector(annotation_base_type_to_use, "base type to use");
93 
94 
95  bool found_base_type = false;
96  if (print_logging) cerr << "About to process base classes" << endl;
97  for (auto base_class : this->decl->bases()) {
98 
99  auto base_qual_type = base_class.getType();
100  auto base_type_decl = base_qual_type->getAsCXXRecordDecl();
101  auto base_type_name = base_type_decl->getNameAsString();
102  auto base_type_canonical_name = get_canonical_name_for_decl(base_type_decl);
103 
104  if (base_type_canonical_name == "class v8toolkit::WrappedClassBase" &&
105  base_class.getAccessSpecifier() != AS_public) {
106  data_error(fmt::format("class inherits from v8toolkit::WrappedClassBase but not publicly: {}",
107  this->class_name).c_str());
108  }
109 
110  cerr << "Base type: " << base_type_canonical_name << endl;
111  if (std::find(annotation_base_types_to_ignore.begin(), annotation_base_types_to_ignore.end(),
112  base_type_canonical_name) !=
113  annotation_base_types_to_ignore.end()) {
114  cerr << "Skipping base type because it was explicitly excluded in annotation on class: "
115  << base_type_name << endl;
116  continue;
117  } else {
118  cerr << "Base type was not explicitly excluded via annotation" << endl;
119  }
120  if (std::find(base_types_to_ignore.begin(), base_types_to_ignore.end(), base_type_canonical_name) !=
121  base_types_to_ignore.end()) {
122  cerr << "Skipping base type because it was explicitly excluded in plugin base_types_to_ignore: "
123  << base_type_name << endl;
124  continue;
125  } else {
126  cerr << "Base type was not explicitly excluded via global ignore list" << endl;
127  }
128  if (!annotation_base_type_to_use.empty() && annotation_base_type_to_use[0] != base_type_name) {
129  cerr << "Skipping base type because it was not the one specified to use via annotation: "
130  << base_type_name << endl;
131  continue;
132  }
133 
134  if (base_qual_type->isDependentType()) {
135  cerr << "-- base type is dependent" << endl;
136  }
137 
138 
139  found_base_type = true;
140  auto base_record_decl = base_qual_type->getAsCXXRecordDecl();
141 
142 // fprintf(stderr, "%s -- type class: %d\n", indentation.c_str(), base_qual_type->getTypeClass());
143 // cerr << indentation << "-- base type has a cxxrecorddecl" << (record_decl != nullptr) << endl;
144 // cerr << indentation << "-- base type has a tagdecl: " << (base_tag_decl != nullptr) << endl;
145 // cerr << indentation << "-- can be cast to tagtype: " << (dyn_cast<TagType>(base_qual_type) != nullptr) << endl;
146 // cerr << indentation << "-- can be cast to attributed type: " << (dyn_cast<AttributedType>(base_qual_type) != nullptr) << endl;
147 // cerr << indentation << "-- can be cast to injected class name type: " << (dyn_cast<InjectedClassNameType>(base_qual_type) != nullptr) << endl;
148 
149 
150  if (base_record_decl == nullptr) {
151  llvm::report_fatal_error("Got null base type record decl - this should be caught ealier");
152  }
153  // printf("Found parent/base class %s\n", record_decl->getNameAsString().c_str());
154 
155  cerr << "getting base type wrapped class object" << endl;
156  WrappedClass &current_base = WrappedClass::get_or_insert_wrapped_class(base_record_decl, this->compiler_instance,
158 
159 
160  auto current_base_include = get_include_for_type_decl(this->compiler_instance, current_base.decl);
161  auto current_include = get_include_for_type_decl(this->compiler_instance, this->decl);
162  // printf("For %s, include %s -- for %s, include %s\n", current_base->class_name.c_str(), current_base_include.c_str(), current->class_name.c_str(), current_include.c_str());
163 
164  this->include_files.insert(current_base_include);
165  current_base.include_files.insert(current_include);
166  this->base_types.insert(&current_base);
167  current_base.derived_types.insert(this);
168 
169  //printf("%s now has %d base classes\n", current->class_name.c_str(), (int)current->base_types.size());
170  //printf("%s now has %d derived classes\n", current_base->class_name.c_str(), (int)current_base->derived_types.size());
171 
172 
173  }
174 
175  if (print_logging) cerr << "done with base classes" << endl;
176  if (must_have_base_type && !found_base_type) {
177  data_error(
178  fmt::format("base_type_to_use specified but no base type found: {}", this->class_name));
179  }
180 
181 
182 
183 
184  // Handle bidirectional class if appropriate
186 
187  // find bidirectional constructor
188  int constructor_parameter_count;
189  vector<QualType> constructor_parameters;
190 
191  // iterate through all constructors with the specified annotation
192  foreach_constructor(this->decl, [&](auto constructor_decl) {
194  data_error(fmt::format("ERROR: Got more than one bidirectional constructor for {}", this->name_alias));
195  return;
196  }
197  this->bidirectional_constructor = constructor_decl;
199 
200  if (this->bidirectional_constructor == nullptr) {
201  this->set_error(fmt::format("Bidirectional class {} doesn't have a bidirectional constructor explicitly set", this->name_alias));
202  }
203 
204  string bidirectional_class_name = fmt::format("JS{}", this->name_alias);
205 
206  // created a WrappedClass for the non-AST JSWrapper class
207  WrappedClass * js_wrapped_class = new WrappedClass(bidirectional_class_name,
208  this->compiler_instance);
209  js_wrapped_class->bidirectional = true;
210  js_wrapped_class->my_include = fmt::format("\"v8toolkit_generated_bidirectional_{}.h\"", this->name_alias);
211  cerr << fmt::format("my_include for bidirectional class: {}" , js_wrapped_class->my_include) << endl;
212 
213  WrappedClass::insert_wrapped_class(js_wrapped_class);
214 
215  js_wrapped_class->base_types.insert(this);
216 
217  cerr << fmt::format("Adding derived bidirectional type {} to base type: {}",
218  js_wrapped_class->class_name, this->name_alias) << endl;
219 
220  // set the bidirectional class as being a subclass of the non-bidirectional type
221  this->derived_types.insert(js_wrapped_class);
222 
223  js_wrapped_class->include_files.insert("<v8toolkit/bidirectional.h>");
224  js_wrapped_class->include_files.insert(js_wrapped_class->my_include);
225  cerr << fmt::format("my_include for bidirectional class: {}" , js_wrapped_class->my_include) << endl;
226  }
227 
228  std::cerr << fmt::format("Done creating WrappedClass for {}", this->name_alias) << std::endl;
229 }
230 
231 
232 
233 set<unique_ptr<ConstructorFunction>> const & WrappedClass::get_constructors() {
234  this->parse_all_methods();
235  return this->constructors;
236 }
237 
238 
239 set<unique_ptr<MemberFunction>> const & WrappedClass::get_member_functions() {
240  this->parse_all_methods();
241  return this->member_functions;
242 }
243 
244 
245 set<unique_ptr<StaticFunction>> const & WrappedClass::get_static_functions() {
246  this->parse_all_methods();
247  return this->static_functions;
248 }
249 
250 
252 
253 
254  if (this->methods_parsed || this->decl == nullptr) {
255  return;
256  }
257 
258 
259  this->methods_parsed = true;
260  std::cerr << fmt::format("*** Parsing class methods") << std::endl;
261 
262  // use decls not methods because methods doesn't give templated functions
263  for (Decl * current_decl : this->decl->decls()) {
264 
265  if (auto using_shadow_decl = dyn_cast<UsingShadowDecl>(current_decl)) {
266  std::cerr << fmt::format("GOT USING SHADOW DECL") << std::endl;
267  auto target_decl = using_shadow_decl->getTargetDecl();
268  std::cerr << fmt::format("target decl name: {}", target_decl->getNameAsString()) << std::endl;
269  std::cerr << fmt::format("target decl is cxxmethoddecl? {}", dyn_cast<CXXMethodDecl>(target_decl) != nullptr) << std::endl;
270 
271  if (dyn_cast<CXXMethodDecl>(target_decl) == nullptr) {
272  llvm::report_fatal_error(
273  fmt::format("UsingShadowDecl target decl not a CXXMethodDecl (don't know how to handle this): {}",
274  target_decl->getNameAsString()));
275  }
276  std::cerr << fmt::format("continuing to parse as if shadow decl target was a method in this class") << std::endl;
277  current_decl = target_decl;
278  }
279 
280  if (auto template_method = dyn_cast<FunctionTemplateDecl>(current_decl)) {
281  std::string full_method_name(template_method->getQualifiedNameAsString());
282  std::cerr << fmt::format("templated member function: {}", full_method_name) << std::endl;
283 
284  auto template_parameters = template_method->getTemplateParameters();
285  for (auto i = template_parameters->begin(); i != template_parameters->end(); i++) {
286  std::cerr << fmt::format("template parameter: {}", (*i)->getNameAsString()) << std::endl;
287  if (auto template_type_param_decl = dyn_cast<TemplateTypeParmDecl>(*i)) {
288  std::cerr << fmt::format("--is a type parameter") << std::endl;
289  if (template_type_param_decl->hasDefaultArgument()) {
290  auto default_type = template_type_param_decl->getDefaultArgument();
291  std::cerr << fmt::format("----has default argument: {}", get_type_string(default_type)) << std::endl;
292  }
293  } else if (auto template_value_param_decl = dyn_cast<ValueDecl>(*i)) {
294  std::cerr << fmt::format("--is a value parameter") << std::endl;
295 
296  } else {
297  std::cerr << fmt::format("--is unknown type of parameter") << std::endl;
298  }
299  }
300 
301 // // find the CXXMethodDecl
302 // for(auto actual_method_decl : template_method->) {
303 //
304 // }
305  }
306 
307  if (auto method = dyn_cast<CXXMethodDecl>(current_decl)) {
308 
309  Annotations method_annotations(method);
310 
311  std::string full_method_name(method->getQualifiedNameAsString());
312  cerr << fmt::format("looking at {}", full_method_name) << endl;
313 
314  if (method->isTemplateDecl()) {
315  std::cerr << fmt::format("{} is template decl", full_method_name) << std::endl;
316  }
317 
318  if (method->hasInheritedPrototype()) {
319  cerr << fmt::format("Skipping method %s because it has inherited prototype", full_method_name) << endl;
320  continue;
321  }
322 
323  auto export_type = get_export_type(method, EXPORT_ALL);
324 
325  if (export_type != EXPORT_ALL && export_type != EXPORT_EXCEPT) {
327  printf("Skipping method %s because not supposed to be exported %d\n",
328  full_method_name.c_str(), export_type);
329  continue;
330  }
331 
332  // only deal with public methods
333  if (method->getAccess() != AS_public) {
334  if (PRINT_SKIPPED_EXPORT_REASONS) printf("**%s is not public, skipping\n", full_method_name.c_str());
335  continue;
336  }
337 
338  // list of overloaded operator enumerated values
339  // http://llvm.org/reports/coverage/tools/clang/include/clang/Basic/OperatorKinds.def.gcov.html
340  if (method->isOverloadedOperator()) {
341 
342  // if it's a call operator (operator()), grab it
343  if (OO_Call == method->getOverloadedOperator()) {
344  // nothing specific to do, just don't skip it only because it's an overloaded operator
345  } else {
346 
347  // otherwise skip overloaded operators
349  printf("**skipping overloaded operator %s\n", full_method_name.c_str());
350  continue;
351  }
352  }
353  if (auto constructor_decl = dyn_cast<CXXConstructorDecl>(method)) {
354 
355  // don't deal with constructors on abstract types
356  if (this->decl->isAbstract()) {
357  continue;
358  }
360  continue;
361  }
362  if (this->force_no_constructors) {
363  continue;
364  }
365 
366 
367  if (constructor_decl->isCopyConstructor()) {
368  fprintf(stderr, "Skipping copy constructor\n");
369  continue;
370  } else if (constructor_decl->isMoveConstructor()) {
371  fprintf(stderr, "Skipping move constructor\n");
372  continue;
373  } else if (constructor_decl->isDeleted()) {
374  if (print_logging) cerr << "Skipping deleted constructor" << endl;
375  continue;
376  }
377 
378  // make sure there's no dupes
379  auto new_constructor = std::make_unique<ConstructorFunction>(*this, constructor_decl);
380  for (auto & existing_constructor : this->constructors) {
381  if (new_constructor->js_name == existing_constructor->js_name) {
382  llvm::report_fatal_error(fmt::format("Duplicate constructor javascript name: {}", new_constructor->js_name));
383  }
384  }
385  this->constructors.insert(std::move(new_constructor));
386  continue;
387  }
388  if (dyn_cast<CXXDestructorDecl>(method)) {
389  if (PRINT_SKIPPED_EXPORT_REASONS) printf("**skipping destructor %s\n", full_method_name.c_str());
390  continue;
391  }
392  if (dyn_cast<CXXConversionDecl>(method)) {
394  printf("**skipping conversion operator %s\n", full_method_name.c_str());
395  continue;
396  }
397 
398 
399  if (method_annotations.has(V8TOOLKIT_EXTEND_WRAPPER_STRING)) {
400  // cerr << "has extend wrapper string" << endl;
401  if (!method->isStatic()) {
402  data_error(fmt::format("method {} annotated with V8TOOLKIT_EXTEND_WRAPPER must be static",
403  full_method_name.c_str()));
404 
405  }
407  cerr << fmt::format(
408  "**skipping static method marked as v8 class wrapper extension method, but will call it during class wrapping")
409  << endl;
410  this->wrapper_extension_methods.insert(full_method_name + "(class_wrapper);");
411  continue; // don't wrap the method as a normal method
412  }
413 
414  // this is VERY similar to the one above and both probably aren't needed, but they do allow SLIGHTLY different capabilities
415  if (method_annotations.has(V8TOOLKIT_CUSTOM_EXTENSION_STRING)) {
416  if (!method->isStatic()) {
417  data_error(fmt::format("method {} annotated with V8TOOLKIT_CUSTOM_EXTENSION must be static",
418  full_method_name.c_str()));
419  }
421  cerr << fmt::format(
422  "**skipping static method marked as V8TOOLKIT_CUSTOM_EXTENSION, but will call it during class wrapping")
423  << endl;
424  this->wrapper_custom_extensions.insert(
425  fmt::format("class_wrapper.add_new_constructor_function_template_callback(&{});",
426  full_method_name));
427  continue; // don't wrap the method as a normal method
428  }
429 
430  std::cerr << fmt::format("Creating ParsedMethod...") << std::endl;
431 
432  if (method->isStatic()) {
433  this->static_functions.insert(make_unique<StaticFunction>(*this, method));
434  } else {
435  this->member_functions.insert(make_unique<MemberFunction>(*this, method));
436  }
437  }
438  }
439 }
440 
441 
442 void WrappedClass::foreach_inheritance_level(function<void(WrappedClass &)> callback) {
443  WrappedClass * current_class = this;
444  while (true) {
445 
446  callback(*current_class);
447 
448  if (current_class->base_types.empty()) {
449  break;
450  }
451  current_class = *current_class->base_types.begin();
452  }
453 
454 }
455 
456 set<unique_ptr<DataMember>> & WrappedClass::get_members() {
457  if (this->members_parsed) {
458  return this->members;
459  }
460  this->members_parsed = true;
461 
462 
463  this->foreach_inheritance_level([&](WrappedClass & wrapped_class) {
464  for (FieldDecl *field : wrapped_class.decl->fields()) {
465 
466  string field_name = field->getQualifiedNameAsString();
467 
468  auto export_type = get_export_type(field, EXPORT_ALL);
469  if (export_type != EXPORT_ALL && export_type != EXPORT_EXCEPT) {
471  printf("Skipping data member %s because not supposed to be exported %d\n",
472  field_name.c_str(), export_type);
473  continue;
474  }
475 
476  if (field->getAccess() != AS_public) {
477  if (PRINT_SKIPPED_EXPORT_REASONS) printf("**%s is not public, skipping\n", field_name.c_str());
478  continue;
479  }
480 
481  this->members.emplace(make_unique<DataMember>(*this, wrapped_class, field));
482  }
483  });
484  return this->members;
485 }
486 
487 
489  decl(nullptr),
490  class_name(class_name),
491  name_alias(class_name),
492  compiler_instance(compiler_instance),
493  valid(true), // explicitly generated, so must be valid
495 {
496  WrappedClass::wrapped_classes.push_back(this);
497 }
498 
499 
500 
502 
503  cerr << fmt::format("Generating js stub for {}", this->name_alias) << endl;
504 
505  stringstream result;
506  string indentation = " ";
507 
508  result << "/**\n";
509  result << fmt::format(" * @class {}\n", this->name_alias);
510 
511  // std::cerr << fmt::format("generating stub for {} data members", this->get_members().size()) << std::endl;
512  for (auto & member : this->get_members()) {
513  result << member->get_js_stub();
514  }
515  result << fmt::format(" **/\n", indentation);
516 
517 
518  result << fmt::format("class {}", this->name_alias);
519 
520  if (this->base_types.size() == 1) {
521  result << fmt::format(" extends {}", (*this->base_types.begin())->name_alias);
522  }
523  result << "{\n";
524 
525  for (auto & constructor : this->get_constructors()) {
526  result << constructor->generate_js_stub();
527  }
528 
529  std::cerr << fmt::format("generating stub for {} methods", this->get_member_functions().size()) << std::endl;
530  for (auto & method : this->get_member_functions()) {
531  result << method->generate_js_stub();
532  }
533 
534  std::cerr << fmt::format("generating stub for {} methods", this->get_static_functions().size()) << std::endl;
535  for (auto & method : this->get_static_functions()) {
536  result << method->generate_js_stub();
537  }
538 
539 
540  result << fmt::format("}}\n\n\n");
541 // fprintf(stderr, "js stub result for class:\n%s", result.str().c_str());
542  return result.str();
543 }
544 
545 
546 
548 
549  cerr << fmt::format("In 'should be wrapped' with class {}, annotations: {}", this->class_name, join(annotations.get())) << endl;
550 
553  cerr << "data error - none and all" << endl;
554  data_error(fmt::format("type has both NONE_STRING and ALL_STRING - this makes no sense", class_name));
555  }
556 
558  cerr << fmt::format("should be wrapped {}- found base class (YES)", this->name_alias) << endl;
559  return true;
560  }
561  if (found_method == FOUND_GENERATED) {
562  cerr << fmt::format("should be wrapped {}- found generated (YES)", this->name_alias) << endl;
563  return true;
564  }
565 
568  cerr << "Found NONE_STRING" << endl;
569  return false;
570  }
571  } else if (found_method == FOUND_ANNOTATION) {
573  cerr << "Found NONE_STRING" << endl;
574  return false;
575  }
577  llvm::report_fatal_error(fmt::format("Type was supposedly found by annotation, but annotation not found: {}", class_name));
578  }
579  } else if (found_method == FOUND_UNSPECIFIED) {
581  cerr << "Found NONE_STRING on UNSPECIFIED" << endl;
582  return false;
583  }
585  cerr << "didn't find all string on UNSPECIFIED" << endl;
586  return false;
587  }
588  cerr << "FOUND_UNSPECIFIED" << endl;
589  return false;
590  }
591 
592  /*
593  // *** IF A TYPE SHOULD BE WRAPPED THAT FORCES ITS PARENT TYPE TO BE WRAPPED ***
594 
595 
596  if (base_types.empty()) {
597  cerr << "no base typ so SHOULD BE WRAPPED" << endl;
598  return true;
599  } else {
600  cerr << "Checking should_be_wrapped for base type" << endl;
601  auto & base_type_wrapped_class = **base_types.begin();
602  cerr << "base type is '" << base_type_wrapped_class.class_name << "'" << endl;
603  return base_type_wrapped_class.should_be_wrapped();
604  }
605  */
606 
607  // if it should be wrapped but there are too many base types, error out
608  if (base_types.size() > 1) {
609  data_error(fmt::format("trying to see if {} should be wrapped but it has more than one base type -- unsupported", class_name));
610  }
611 
612  cerr << "should be wrapped -- fall through returning true (YES)" << endl;
613  return true;
614 }
615 
616 
617 bool WrappedClass::ready_for_wrapping(set<WrappedClass *> dumped_classes) const {
618 
619 
620 
621  // don't double wrap yourself
622  if (find(dumped_classes.begin(), dumped_classes.end(), this) != dumped_classes.end()) {
623  printf("Already wrapped %s\n", class_name.c_str());
624  return false;
625  }
626 
627  if (!should_be_wrapped()) {
628  cerr << "should be wrapped returned false" << endl;
629  return false;
630  }
631 
632  /*
633  // if all this class's directly derived types have been wrapped, then we're good since their
634  // dependencies would have to be met for them to be wrapped
635  for (auto derived_type : derived_types) {
636  if (find(dumped_classes.begin(), dumped_classes.end(), derived_type) == dumped_classes.end()) {
637  printf("Couldn't find %s\n", derived_type->class_name.c_str());
638  return false;
639  }
640  }
641  */
642  for (auto base_type : base_types) {
643  if (find(dumped_classes.begin(), dumped_classes.end(), base_type) == dumped_classes.end()) {
644  printf("base type %s not already wrapped - return false\n", base_type->class_name.c_str());
645  return false;
646  }
647  }
648 
649  printf("Ready to wrap %s\n", class_name.c_str());
650 
651  return true;
652 }
653 
654 
655 
657  stringstream result;
658  string indentation = " ";
659 
660  result << indentation << "{\n";
661  result << fmt::format("{} // {}", indentation, class_name) << "\n";
662  result << fmt::format("{} v8toolkit::V8ClassWrapper<{}> & class_wrapper = isolate.wrap_class<{}>();\n",
663  indentation, this->class_name, this->class_name);
664  result << fmt::format("{} class_wrapper.set_class_name(\"{}\");\n", indentation, name_alias);
665 
666  for(auto & method : this->get_member_functions()) {
667  result << method->generate_js_bindings();
668  }
669 
670  for(auto & method : this->get_static_functions()) {
671  result << method->generate_js_bindings();
672  }
673 
674  for(auto & member : members) {
675  result << member->get_bindings();
676  }
677  for(auto & wrapper_extension_method : wrapper_extension_methods) {
678  result << fmt::format("{} {}\n", indentation, wrapper_extension_method);
679  }
680  for(auto & wrapper_custom_extension : wrapper_custom_extensions) {
681  result << fmt::format("{} {}\n", indentation, wrapper_custom_extension);
682  }
683 
684  if (!derived_types.empty()) {
685  result << fmt::format("{} class_wrapper.set_compatible_types<{}>();\n", indentation,
687  }
688  if (get_base_class_string() != "") {
689  result << fmt::format("{} class_wrapper.set_parent_type<{}>();\n", indentation,
691  }
692  result << fmt::format("{} class_wrapper.finalize(true);\n", indentation);
693 
694  // if there are no constructors but there are static methods, expose the static methods with this non-constructor name
695  if (this->get_constructors().empty() && this->has_static_method()) {
696  result << fmt::format("{} class_wrapper.expose_static_methods(\"{}\", isolate);\n", indentation, this->name_alias);
697  }
698  // otherwise just create any constructors that may need wrapping (none is fine)
699  else {
700  for (auto & constructor : this->get_constructors()) {
701  result << constructor->generate_js_bindings();
702  }
703  }
704 
705  result << indentation << "}\n\n";
706  return result.str();
707 }
708 
709 
710 void WrappedClass::add_member_name(string const & name) {
711  // it's ok to have duplicate names, but then this class can not be wrapped
712  if (this->used_member_names.count(name) > 0) {
713  this->set_error(fmt::format("duplicate name: {}", name));
714  }
715  this->used_member_names.insert(name);
716 }
717 
718 void WrappedClass::add_static_name(string const & name) {
719  // it's ok to have duplicate names, but then this class can not be wrapped
720  if (this->used_static_names.count(name) > 0) {
721  this->set_error(fmt::format("duplicate name: {}", name));
722  }
723  this->used_static_names.insert(name);
724 }
725 
726 
727 
728 
729 void WrappedClass::set_error(string const & error_message) {
730  this->data_errors.push_back(error_message);
731  this->valid = false;
732 }
733 
734 
735 
736 // return all the header files for all the types used by all the base types of the specified type
738  set<string> results{this->my_include};
739  results.insert(this->include_files.begin(), this->include_files.end());
740  //std::cerr << fmt::format("adding base type include for {} with {} base types", this->class_name, this->base_types.size()) << std::endl;
741 
742  //cerr << "Includes at this level: " << endl;
743 // for (auto include : results) {
744 // cerr << include << endl;
745 // }
746 
747  for (WrappedClass * base_class : this->base_types) {
748  //cerr << fmt::format("...base type: {}", base_class->name_alias) << endl;
749  auto base_results = base_class->get_base_type_includes();
750  results.insert(base_results.begin(), base_results.end());
751  }
752  // std::cerr << fmt::format("done adding base type include for {}", this->class_name) << std::endl;
753 
754  return results;
755 }
756 
758  cerr << fmt::format("Getting derived type includes for {}", name_alias) << endl;
759  set<string> results;
760  results.insert(my_include);
761  for (auto derived_type : derived_types) {
762 
763  std::cerr << fmt::format("1 - derived type loop for {}", derived_type->name_alias) << std::endl;
764  results.insert(derived_type->include_files.begin(), derived_type->include_files.end());
765  //std::cerr << fmt::format("2") << std::endl;
766  auto derived_includes = derived_type->get_derived_type_includes();
767  //std::cerr << fmt::format("3") << std::endl;
768  results.insert(derived_includes.begin(), derived_includes.end());
769  //std::cerr << fmt::format("4") << std::endl;
770  cerr << fmt::format("{}: Derived type includes for subclass {} and all its derived classes: {}", name_alias, derived_type->class_name, join(derived_includes)) << endl;
771 
772  }
773  //std::cerr << fmt::format("aaa") << std::endl;
774  return results;
775 }
776 
777 
778 
780  if (this->decl == nullptr) {
781  return false;
782  }
783  return dyn_cast<ClassTemplateSpecializationDecl>(decl);
784 }
785 
786 
787 
789  return
790  this->found_method == FOUND_ANNOTATION ||
791  this->found_method == FOUND_INHERITANCE ||
792  this->found_method == FOUND_GENERATED ||
794 
795 }
796 
797 
void set_error(string const &error_message)
bool bidirectional
Definition: wrapped_class.h:85
void add_member_name(string const &name)
vector< string > data_errors
Definition: wrapped_class.h:63
FOUND_METHOD
#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
int print_logging
WrappedClass()=default
std::string get_derived_classes_string(int level=0, const std::string indent="")
::std::string string
Definition: gtest-port.h:1097
void data_error(const string &error)
map< string, int > template_instantiations
const vector< string > get() const
Definition: annotations.h:42
void update_wrapped_class_for_type(WrappedClass &wrapped_class, QualType qual_type)
std::string get_base_class_string()
bool found_method_means_wrapped()
std::string get_type_string(QualType qual_type, const std::string &indentation)
bool should_be_wrapped() const
static vector< WrappedClass * > wrapped_classes
Definition: wrapped_class.h:29
#define V8TOOLKIT_CUSTOM_EXTENSION_STRING
Definition: class_parser.h:127
void parse_all_methods()
void merge(const Annotations &other)
Definition: annotations.h:71
set< string > wrapper_extension_methods
Definition: wrapped_class.h:69
set< string > used_static_names
Definition: wrapped_class.h:62
#define V8TOOLKIT_BIDIRECTIONAL_CONSTRUCTOR_STRING
Definition: class_parser.h:107
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
#define V8TOOLKIT_IGNORE_BASE_TYPE_PREFIX
Definition: class_parser.h:84
bool is_template_specialization()
set< string > wrapper_custom_extensions
Definition: wrapped_class.h:70
#define V8TOOLKIT_BIDIRECTIONAL_CLASS_STRING
Definition: class_parser.h:106
bool force_no_constructors
Definition: wrapped_class.h:80
CXXConstructorDecl const * bidirectional_constructor
Definition: wrapped_class.h:86
#define PRINT_SKIPPED_EXPORT_REASONS
Definition: class_handler.h:5
string my_include
Definition: wrapped_class.h:73
std::string generate_js_stub()
FOUND_METHOD found_method
Definition: wrapped_class.h:79
std::vector< string > get_regex(const string &regex_string) const
Definition: annotations.h:51
set< unique_ptr< StaticFunction > > const & get_static_functions()
set< WrappedClass * > base_types
tracked base_types - if it&#39;s more than one, that&#39;s a data error because javascript only allows one ...
Definition: wrapped_class.h:67
EXPORT_TYPE get_export_type(const NamedDecl *decl, EXPORT_TYPE previous)
#define V8TOOLKIT_NONE_STRING
Definition: class_parser.h:17
std::set< string > get_derived_type_includes()
bool has(const std::string &target) const
Definition: annotations.h:67
void foreach_inheritance_level(function< void(WrappedClass &)> callback)
set< WrappedClass * > derived_types
Definition: wrapped_class.h:64
static void insert_wrapped_class(WrappedClass *wrapped_class)
bool has_static_method()
Definition: wrapped_class.h:95
set< unique_ptr< DataMember > > & get_members()
void add_static_name(string const &name)
string class_name
Definition: wrapped_class.h:43
#define V8TOOLKIT_EXTEND_WRAPPER_STRING
Definition: class_parser.h:20
std::string get_canonical_name_for_decl(const TypeDecl *decl)
CXXRecordDecl const * decl
Definition: wrapped_class.h:31
set< unique_ptr< ConstructorFunction > > const & get_constructors()
static map< const CXXRecordDecl *, string > names_for_record_decls
Definition: annotations.h:88
set< string > used_member_names
Definition: wrapped_class.h:61
Annotations annotations
Definition: wrapped_class.h:76
std::string get_bindings()
vector< string > base_types_to_ignore
set< unique_ptr< MemberFunction > > const & get_member_functions()
std::set< string > get_base_type_includes()
std::string join(const T &source, const std::string &between=", ", bool leading_between=false)
CompilerInstance & compiler_instance
Definition: wrapped_class.h:71
bool ready_for_wrapping(set< WrappedClass * > dumped_classes) const
#define V8TOOLKIT_DO_NOT_WRAP_CONSTRUCTORS_STRING
Definition: class_parser.h:102
#define V8TOOLKIT_USE_BASE_TYPE_PREFIX
Definition: class_parser.h:94
const T & move(const T &t)
Definition: gtest-port.h:1317
void foreach_constructor(const CXXRecordDecl *klass, Callback &&callback, const std::string &annotation="")
void print_vector(const vector< string > &vec, const string &header, const string &indentation, bool ignore_empty)