13 name_alias(decl->getTypeForDecl()->getCanonicalTypeInternal().getAsString()),
14 compiler_instance(compiler_instance),
17 found_method(found_method)
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);
22 if (!using_name.empty()) {
23 cerr << fmt::format(
"Setting name alias for {} to {} because of a 'using' statement",
class_name, using_name) << endl;
33 cerr <<
"Top of WrappedClass constructor body" << endl;
35 fprintf(stderr,
"%p\n", (
void *)decl);
36 llvm::report_fatal_error(
"Empty name string for decl");
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));
51 if (
auto specialization = dyn_cast<ClassTemplateSpecializationDecl>(this->decl)) {
57 this->decl->getTypeForDecl()->getCanonicalTypeInternal());
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();
67 cerr <<
"Final wrapped class annotations: " << endl;
73 bool must_have_base_type =
false;
78 if (annotation_base_type_to_use.size() > 1) {
83 if (!annotation_base_type_to_use.empty()) {
84 must_have_base_type =
true;
91 print_vector(annotation_base_types_to_ignore,
"base types to ignore");
92 print_vector(annotation_base_type_to_use,
"base type to use");
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()) {
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();
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: {}",
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;
118 cerr <<
"Base type was not explicitly excluded via annotation" << endl;
122 cerr <<
"Skipping base type because it was explicitly excluded in plugin base_types_to_ignore: " 123 << base_type_name << endl;
126 cerr <<
"Base type was not explicitly excluded via global ignore list" << endl;
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;
134 if (base_qual_type->isDependentType()) {
135 cerr <<
"-- base type is dependent" << endl;
139 found_base_type =
true;
140 auto base_record_decl = base_qual_type->getAsCXXRecordDecl();
150 if (base_record_decl ==
nullptr) {
151 llvm::report_fatal_error(
"Got null base type record decl - this should be caught ealier");
155 cerr <<
"getting base type wrapped class object" << endl;
176 if (must_have_base_type && !found_base_type) {
178 fmt::format(
"base_type_to_use specified but no base type found: {}", this->
class_name));
188 int constructor_parameter_count;
189 vector<QualType> constructor_parameters;
194 data_error(fmt::format(
"ERROR: Got more than one bidirectional constructor for {}", this->
name_alias));
201 this->
set_error(fmt::format(
"Bidirectional class {} doesn't have a bidirectional constructor explicitly set", this->
name_alias));
204 string bidirectional_class_name = fmt::format(
"JS{}", this->
name_alias);
208 this->compiler_instance);
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;
217 cerr << fmt::format(
"Adding derived bidirectional type {} to base type: {}",
218 js_wrapped_class->
class_name, this->name_alias) << endl;
223 js_wrapped_class->
include_files.insert(
"<v8toolkit/bidirectional.h>");
225 cerr << fmt::format(
"my_include for bidirectional class: {}" , js_wrapped_class->
my_include) << endl;
228 std::cerr << fmt::format(
"Done creating WrappedClass for {}", this->
name_alias) << std::endl;
235 return this->constructors;
241 return this->member_functions;
247 return this->static_functions;
254 if (this->methods_parsed || this->
decl ==
nullptr) {
259 this->methods_parsed =
true;
260 std::cerr << fmt::format(
"*** Parsing class methods") << std::endl;
263 for (Decl * current_decl : this->
decl->decls()) {
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;
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()));
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;
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;
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;
293 }
else if (
auto template_value_param_decl = dyn_cast<ValueDecl>(*
i)) {
294 std::cerr << fmt::format(
"--is a value parameter") << std::endl;
297 std::cerr << fmt::format(
"--is unknown type of parameter") << std::endl;
307 if (
auto method = dyn_cast<CXXMethodDecl>(current_decl)) {
311 std::string full_method_name(method->getQualifiedNameAsString());
312 cerr << fmt::format(
"looking at {}", full_method_name) << endl;
314 if (method->isTemplateDecl()) {
315 std::cerr << fmt::format(
"{} is template decl", full_method_name) << std::endl;
318 if (method->hasInheritedPrototype()) {
319 cerr << fmt::format(
"Skipping method %s because it has inherited prototype", full_method_name) << endl;
327 printf(
"Skipping method %s because not supposed to be exported %d\n",
328 full_method_name.c_str(), export_type);
333 if (method->getAccess() != AS_public) {
340 if (method->isOverloadedOperator()) {
343 if (OO_Call == method->getOverloadedOperator()) {
349 printf(
"**skipping overloaded operator %s\n", full_method_name.c_str());
353 if (
auto constructor_decl = dyn_cast<CXXConstructorDecl>(method)) {
356 if (this->
decl->isAbstract()) {
367 if (constructor_decl->isCopyConstructor()) {
368 fprintf(stderr,
"Skipping copy constructor\n");
370 }
else if (constructor_decl->isMoveConstructor()) {
371 fprintf(stderr,
"Skipping move constructor\n");
373 }
else if (constructor_decl->isDeleted()) {
374 if (
print_logging) cerr <<
"Skipping deleted constructor" << endl;
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));
385 this->constructors.insert(
std::move(new_constructor));
388 if (dyn_cast<CXXDestructorDecl>(method)) {
392 if (dyn_cast<CXXConversionDecl>(method)) {
394 printf(
"**skipping conversion operator %s\n", full_method_name.c_str());
401 if (!method->isStatic()) {
402 data_error(fmt::format(
"method {} annotated with V8TOOLKIT_EXTEND_WRAPPER must be static",
403 full_method_name.c_str()));
408 "**skipping static method marked as v8 class wrapper extension method, but will call it during class wrapping")
416 if (!method->isStatic()) {
417 data_error(fmt::format(
"method {} annotated with V8TOOLKIT_CUSTOM_EXTENSION must be static",
418 full_method_name.c_str()));
422 "**skipping static method marked as V8TOOLKIT_CUSTOM_EXTENSION, but will call it during class wrapping")
425 fmt::format(
"class_wrapper.add_new_constructor_function_template_callback(&{});",
430 std::cerr << fmt::format(
"Creating ParsedMethod...") << std::endl;
432 if (method->isStatic()) {
433 this->static_functions.insert(make_unique<StaticFunction>(*
this, method));
435 this->member_functions.insert(make_unique<MemberFunction>(*
this, method));
446 callback(*current_class);
451 current_class = *current_class->
base_types.begin();
457 if (this->members_parsed) {
458 return this->members;
460 this->members_parsed =
true;
464 for (FieldDecl *field : wrapped_class.
decl->fields()) {
466 string field_name = field->getQualifiedNameAsString();
471 printf(
"Skipping data member %s because not supposed to be exported %d\n",
472 field_name.c_str(), export_type);
476 if (field->getAccess() != AS_public) {
481 this->members.emplace(make_unique<DataMember>(*
this, wrapped_class, field));
484 return this->members;
490 class_name(class_name),
492 compiler_instance(compiler_instance),
503 cerr << fmt::format(
"Generating js stub for {}", this->
name_alias) << endl;
506 string indentation =
" ";
509 result << fmt::format(
" * @class {}\n", this->
name_alias);
513 result << member->get_js_stub();
515 result << fmt::format(
" **/\n", indentation);
518 result << fmt::format(
"class {}", this->
name_alias);
526 result << constructor->generate_js_stub();
529 std::cerr << fmt::format(
"generating stub for {} methods", this->
get_member_functions().size()) << std::endl;
531 result << method->generate_js_stub();
534 std::cerr << fmt::format(
"generating stub for {} methods", this->
get_static_functions().size()) << std::endl;
536 result << method->generate_js_stub();
540 result << fmt::format(
"}}\n\n\n");
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));
558 cerr << fmt::format(
"should be wrapped {}- found base class (YES)", this->
name_alias) << endl;
562 cerr << fmt::format(
"should be wrapped {}- found generated (YES)", this->
name_alias) << endl;
568 cerr <<
"Found NONE_STRING" << endl;
573 cerr <<
"Found NONE_STRING" << endl;
577 llvm::report_fatal_error(fmt::format(
"Type was supposedly found by annotation, but annotation not found: {}",
class_name));
581 cerr <<
"Found NONE_STRING on UNSPECIFIED" << endl;
585 cerr <<
"didn't find all string on UNSPECIFIED" << endl;
588 cerr <<
"FOUND_UNSPECIFIED" << endl;
609 data_error(fmt::format(
"trying to see if {} should be wrapped but it has more than one base type -- unsupported",
class_name));
612 cerr <<
"should be wrapped -- fall through returning true (YES)" << endl;
622 if (find(dumped_classes.begin(), dumped_classes.end(),
this) != dumped_classes.end()) {
623 printf(
"Already wrapped %s\n",
class_name.c_str());
628 cerr <<
"should be wrapped returned false" << endl;
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());
649 printf(
"Ready to wrap %s\n",
class_name.c_str());
658 string indentation =
" ";
660 result << indentation <<
"{\n";
661 result << fmt::format(
"{} // {}", indentation,
class_name) <<
"\n";
662 result << fmt::format(
"{} v8toolkit::V8ClassWrapper<{}> & class_wrapper = isolate.wrap_class<{}>();\n",
664 result << fmt::format(
"{} class_wrapper.set_class_name(\"{}\");\n", indentation,
name_alias);
667 result << method->generate_js_bindings();
671 result << method->generate_js_bindings();
674 for(
auto & member : members) {
675 result << member->get_bindings();
678 result << fmt::format(
"{} {}\n", indentation, wrapper_extension_method);
681 result << fmt::format(
"{} {}\n", indentation, wrapper_custom_extension);
685 result << fmt::format(
"{} class_wrapper.set_compatible_types<{}>();\n", indentation,
689 result << fmt::format(
"{} class_wrapper.set_parent_type<{}>();\n", indentation,
692 result << fmt::format(
"{} class_wrapper.finalize(true);\n", indentation);
696 result << fmt::format(
"{} class_wrapper.expose_static_methods(\"{}\", isolate);\n", indentation, this->
name_alias);
701 result << constructor->generate_js_bindings();
705 result << indentation <<
"}\n\n";
713 this->
set_error(fmt::format(
"duplicate name: {}", name));
721 this->
set_error(fmt::format(
"duplicate name: {}", name));
749 auto base_results = base_class->get_base_type_includes();
750 results.insert(base_results.begin(), base_results.end());
758 cerr << fmt::format(
"Getting derived type includes for {}",
name_alias) << endl;
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());
766 auto derived_includes = derived_type->get_derived_type_includes();
768 results.insert(derived_includes.begin(), derived_includes.end());
770 cerr << fmt::format(
"{}: Derived type includes for subclass {} and all its derived classes: {}",
name_alias, derived_type->class_name,
join(derived_includes)) << endl;
780 if (this->
decl ==
nullptr) {
783 return dyn_cast<ClassTemplateSpecializationDecl>(
decl);
void set_error(string const &error_message)
void add_member_name(string const &name)
vector< string > data_errors
#define V8TOOLKIT_ALL_STRING
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++ ...
std::string get_derived_classes_string(int level=0, const std::string indent="")
void data_error(const string &error)
map< string, int > template_instantiations
const vector< string > get() const
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
#define V8TOOLKIT_CUSTOM_EXTENSION_STRING
void merge(const Annotations &other)
set< string > wrapper_extension_methods
set< string > used_static_names
#define V8TOOLKIT_BIDIRECTIONAL_CONSTRUCTOR_STRING
set< string > include_files
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
bool is_template_specialization()
set< string > wrapper_custom_extensions
#define V8TOOLKIT_BIDIRECTIONAL_CLASS_STRING
bool force_no_constructors
CXXConstructorDecl const * bidirectional_constructor
#define PRINT_SKIPPED_EXPORT_REASONS
std::string generate_js_stub()
FOUND_METHOD found_method
std::vector< string > get_regex(const string ®ex_string) const
set< unique_ptr< StaticFunction > > const & get_static_functions()
set< WrappedClass * > base_types
tracked base_types - if it's more than one, that's a data error because javascript only allows one ...
EXPORT_TYPE get_export_type(const NamedDecl *decl, EXPORT_TYPE previous)
#define V8TOOLKIT_NONE_STRING
std::set< string > get_derived_type_includes()
bool has(const std::string &target) const
void foreach_inheritance_level(function< void(WrappedClass &)> callback)
set< WrappedClass * > derived_types
static void insert_wrapped_class(WrappedClass *wrapped_class)
set< unique_ptr< DataMember > > & get_members()
void add_static_name(string const &name)
#define V8TOOLKIT_EXTEND_WRAPPER_STRING
std::string get_canonical_name_for_decl(const TypeDecl *decl)
CXXRecordDecl const * decl
set< unique_ptr< ConstructorFunction > > const & get_constructors()
static map< const CXXRecordDecl *, string > names_for_record_decls
set< string > used_member_names
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
bool ready_for_wrapping(set< WrappedClass * > dumped_classes) const
#define V8TOOLKIT_DO_NOT_WRAP_CONSTRUCTORS_STRING
#define V8TOOLKIT_USE_BASE_TYPE_PREFIX
const T & move(const T &t)
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)