52 #define TEMPLATE_FILTER_STD 54 #define TEMPLATED_CLASS_PRINT_THRESHOLD 10 55 #define TEMPLATED_FUNCTION_PRINT_THRESHOLD 100 83 {
"^(?:std::|eastl::)?(?:vector_)?(?:multi)?map",
"Object.{$1, $2}"},
85 {
"^(?:const)?\\s*(?:unsigned)?\\s*(?:char|short|int|long|long long|float|double|long double)\\s*(?:const)?\\s*[*]?\\s*[&]?$",
"Number"},
86 {
"^(?:const)?\\s*_?[Bb]ool\\s*(?:const)?\\s*[*]?\\s*[&]?$",
"Boolean"},
87 {
"^(?:const)?\\s*(?:char\\s*[*]|(?:std::)?string)\\s*(?:const)?\\s*\\s*[&]?$",
"String"},
88 {
"^void$",
"Undefined"},
89 {
"^(?:std::)?unique_ptr",
"$1"},
90 {
"^(?:std::)?basic_string",
"String"},
91 {
"^\\s*nullptr\\s*$",
"null"}
117 function println(s){}
129 function printobj(o){}
135 function printobjall(o){}
142 function require(module_name){}
153 #include <fmt/ostream.h> 200 void print_vector(
const vector<string> & vec,
const string & header,
const string & indentation,
bool ignore_empty) {
202 if (ignore_empty && vec.empty()) {
207 cerr << indentation << header << endl;
209 for (
auto & str : vec) {
210 cerr << indentation <<
" - " << str << endl;
213 cerr << indentation <<
" * (EMPTY VECTOR)" << endl;
222 if (decl ==
nullptr) {
226 if (!decl->isThisDeclarationADefinition()) {
230 for (
auto base : decl->bases()) {
231 if (base.getType().getTypePtrOrNull() ==
nullptr) {
232 llvm::report_fatal_error(fmt::format(
"base type ptr was null for {}", decl->getNameAsString()).c_str());
245 auto include_source_location = compiler_instance.getPreprocessor().getSourceManager().getIncludeLoc(file_id);
248 if (include_source_location.isValid()) {
249 auto header_file = include_source_location.printToString(compiler_instance.getPreprocessor().getSourceManager());
259 const char * text = compiler_instance.getPreprocessor().getSourceManager().getCharacterData(include_source_location, &invalid);
260 const char * text_end = text + 1;
261 while(*text_end !=
'>' && *text_end !=
'"') {
265 return string(text, (text_end - text) + 1);
271 auto full_source_loc = FullSourceLoc(source_location, compiler_instance.getPreprocessor().getSourceManager());
273 auto file_id = full_source_loc.getFileID();
278 if (type_decl ==
nullptr) {
296 std::string text = Lexer::getSourceText(CharSourceRange::getTokenRange(source_range), sm, LangOptions(), 0);
297 if (!text.empty() && text.at(text.size()-1) ==
',')
298 return Lexer::getSourceText(CharSourceRange::getCharRange(source_range), sm, LangOptions(), 0);
303 vector<string> count_top_level_template_parameters(
const std::string & source) {
304 int open_angle_count = 0;
305 vector<string> parameter_strings;
307 for (
char c : source) {
313 if (open_angle_count > 1) {
316 }
else if (c ==
'>') {
318 if (open_angle_count > 0) {
322 if (open_angle_count == 1) {
323 if (parameter_strings.size() == 0) {
324 parameter_strings.push_back(
"");
325 current = ¶meter_strings.back();
328 parameter_strings.push_back(
"");
329 current = ¶meter_strings.back();
330 if (open_angle_count > 1) {
336 }
else if (open_angle_count > 1) {
341 if (
print_logging)
if (
print_logging) cerr <<
"^^^^^^^^^^^^^^^ Counted " << parameter_strings.size() <<
" for " << source << endl;
342 for (
auto & str : parameter_strings) {
345 return parameter_strings;
356 const ClassTemplateDecl *
decl;
357 int instantiations = 0;
360 name = decl->getQualifiedNameAsString();
369 for(
auto & tmpl : class_templates) {
370 if (tmpl->decl == decl) {
374 class_templates.emplace_back(make_unique<ClassTemplate>(decl));
375 return *class_templates.back();
387 int instantiations = 0;
390 name = decl->getQualifiedNameAsString();
399 for(
auto & tmpl : function_templates) {
400 if (tmpl->decl == decl) {
404 function_templates.emplace_back(make_unique<FunctionTemplate>(decl));
405 return *function_templates.back();
432 for (
auto & wrapped_class : WrappedClass::wrapped_classes) {
434 if (wrapped_class->class_name == class_name) {
446 vector<string> sfinaes;
447 string forward_declarations =
"#define V8TOOLKIT_V8CLASSWRAPPER_FORWARD_DECLARATIONS ";
448 for (
auto & wrapped_class : wrapped_classes) {
452 if (!wrapped_class->should_be_wrapped()) {
455 sfinaes.emplace_back(wrapped_class->make_sfinae_to_match_wrapped_class());
456 forward_declarations += wrapped_class->class_name +
"; ";
460 for(
int i = sfinaes.size() - 1; i >= 0; i--) {
461 if (sfinaes[i] ==
"") {
462 sfinaes.erase(sfinaes.begin() + i);
468 if (sfinaes.size() > 40 ) {
469 cerr <<
join(sfinaes,
" || ") << endl;
470 llvm::report_fatal_error(
"more 'sfinae's than arbitrary number used to catch likely errors - can be increased if needed");
476 if (!sfinaes.empty()) {
477 sfinae =
string(
"#define V8TOOLKIT_V8CLASSWRAPPER_FULL_TEMPLATE_SFINAE ") +
join(sfinaes,
" || ") +
"\n";
480 forward_declarations +=
"\n";
481 return sfinae +
"\n" + forward_declarations;
515 bool is_trivial_std_type(QualType & qual_type,
std::string & output) {
517 std::string canonical_name = qual_type.getCanonicalType().getAsString();
520 if (std::regex_match(name, regex(
"^(const\\s+|volatile\\s+)*(class\\s+|struct\\s+)?std::[^<]*$"))) {
521 output = handle_std(name);a
525 else if (has_std(canonical_name) &&
526 std::regex_match(name, regex(
"^[^<]*$"))) {
527 output = handle_std(name);
535 bool is_nontrivial_std_type(QualType & qual_type,
std::string & output) {
538 std::string canonical_name = qual_type.getCanonicalType().getAsString();
539 if (
print_logging) cerr <<
"Checking nontrivial std type on " << name <<
" : " << canonical_name << endl;
544 if (has_std(canonical_name) &&
545 std::regex_match(name, matches, regex(
"^([^<]*<).*$"))) {
546 output = handle_std(matches[1].str());
560 auto original_qualifiers = qual_type.getLocalFastQualifiers();
562 while (
auto typedef_type = dyn_cast<TypedefType>(qual_type)) {
563 qual_type = typedef_type->getDecl()->getUnderlyingType();
567 qual_type.setLocalFastQualifiers(original_qualifiers);
569 auto canonical_qual_type = qual_type.getCanonicalType();
571 static PrintingPolicy pp = PrintingPolicy(LangOptions());
572 pp.adjustForCPlusPlus();
573 auto canonical = canonical_qual_type.getAsString(pp);
574 return regex_replace(canonical, regex(
"std::__1::"),
"std::");
579 bool turn_logging_off =
false;
587 if (
print_logging) cerr << indentation <<
"Started at " << qual_type.getAsString() << endl;
588 if (
print_logging) cerr << indentation <<
" And canonical name: " << qual_type.getCanonicalType().getAsString() << endl;
589 if (
print_logging) cerr << indentation <<
" And source " << source << endl;
592 if (is_trivial_std_type(qual_type, std_result)) {
593 if (
print_logging) cerr << indentation <<
"Returning trivial std:: type: " << std_result << endl << endl;
598 bool is_reference = qual_type->isReferenceType();
599 string reference_suffix = is_reference ?
"&" :
"";
600 qual_type = qual_type.getNonReferenceType();
602 stringstream pointer_suffix;
606 if (!qual_type->getPointeeType().isNull()) {
608 pointer_suffix <<
"*";
609 qual_type = qual_type->getPointeeType();
610 if (
print_logging) cerr << indentation <<
"stripped pointer, went to: " << qual_type.getAsString() << endl;
615 if (dyn_cast<TypedefType>(qual_type) !=
nullptr) {
617 if (
print_logging) cerr << indentation <<
"stripped typedef, went to: " << qual_type.getAsString() << endl;
618 qual_type = dyn_cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType();
623 if (
print_logging) cerr << indentation <<
"CHECKING TO SEE IF " << qual_type.getUnqualifiedType().getAsString() <<
" is a template specialization"<< endl;
624 auto base_type_record_decl = qual_type.getUnqualifiedType()->getAsCXXRecordDecl();
625 if (dyn_cast<ClassTemplateSpecializationDecl>(base_type_record_decl)) {
629 if (
print_logging) cerr << indentation <<
"!!!!! Started with template specialization: " << qual_type.getAsString() << endl;
634 string qual_type_string = qual_type.getAsString();
637 bool nontrivial_std_type =
false;
638 if (is_nontrivial_std_type(qual_type, std_type_output)) {
639 if (
print_logging) cerr << indentation <<
"is nontrivial std type and got result: " << std_type_output << endl;
640 nontrivial_std_type =
true;
641 result << std_type_output;
644 else if (!regex_match(qual_type_string, matches, regex(
"^([^<]+<).*(>[^>]*)$"))) {
645 if (
print_logging) cerr << indentation <<
"short circuiting on " << original_qual_type.getAsString() << endl;
647 return original_qual_type.getAsString();
649 result << matches[1];
650 if (
print_logging) cerr << indentation <<
"is NOT nontrivial std type" << endl;
652 auto template_specialization_decl = dyn_cast<ClassTemplateSpecializationDecl>(base_type_record_decl);
654 auto user_specified_template_parameters = count_top_level_template_parameters(source);
657 auto & template_arg_list = template_specialization_decl->getTemplateArgs();
658 if (user_specified_template_parameters.size() > template_arg_list.size()) {
659 llvm::report_fatal_error(fmt::format(
"ERROR: detected template parameters > actual list size for {}", qual_type_string).c_str());
662 auto template_types_to_handle = user_specified_template_parameters.size();
665 template_types_to_handle = template_arg_list.size();
669 for (decltype(template_arg_list.size()) i = 0; i < template_types_to_handle; i++) {
673 if (
print_logging) cerr << indentation <<
"Working on template parameter " << i << endl;
674 auto & arg = template_arg_list[i];
676 switch(arg.getKind()) {
677 case clang::TemplateArgument::Type: {
678 if (
print_logging) cerr << indentation <<
"processing as type argument" << endl;
679 auto template_arg_qual_type = arg.getAsType();
682 if (
print_logging) cerr << indentation <<
"About to append " << template_type_string <<
" template type string onto existing: " << result.str() << endl;
683 result << template_type_string;
685 case clang::TemplateArgument::Integral: {
686 if (
print_logging) cerr << indentation <<
"processing as integral argument" << endl;
687 auto integral_value = arg.getAsIntegral();
688 if (
print_logging) cerr << indentation <<
"integral value radix10: " << integral_value.toString(10) << endl;
689 result << integral_value.toString(10);
692 if (
print_logging) cerr << indentation <<
"Oops, unhandled argument type" << endl;
695 result <<
">" << pointer_suffix.str() << reference_suffix;
696 if (
print_logging) cerr << indentation <<
"!!!!!Finished stringifying templated type to: " << result.str() << endl << endl;
723 auto canonical_qual_type = original_qual_type.getCanonicalType();
727 if (
print_logging) cerr << indentation <<
"returning canonical: " << canonical_qual_type.getAsString() << endl << endl;
730 return canonical_qual_type.getAsString();
743 const CXXMethodDecl * method,
744 const string & annotation =
"") {
745 vector<string> results;
746 auto parameter_count = method->getNumParams();
747 for (
unsigned int i = 0; i < parameter_count; i++) {
748 auto param_decl = method->getParamDecl(i);
750 if (param_decl->hasDefaultArg()) {
751 auto default_argument = param_decl->getDefaultArg();
752 auto source_range = default_argument->getSourceRange();
754 results.push_back(source);
756 results.push_back(
"");
764 const CXXMethodDecl * method,
765 string const & annotation) {
766 vector<QualType> results;
767 auto parameter_count = method->getNumParams();
768 for (
unsigned int i = 0; i < parameter_count; i++) {
769 auto param_decl = method->getParamDecl(i);
773 if (annotation !=
"" && !annotations.
has(annotation)) {
774 if (
print_logging) cerr <<
"Skipping method parameter because it didn't have requested annotation: " << annotation << endl;
777 auto param_qual_type = param_decl->getType();
778 results.push_back(param_qual_type);
784 vector<string> results;
785 for (std::size_t i = 0; i < qual_types.size(); i++) {
786 if (with_std_move && qual_types[i]->isRValueReferenceType()) {
787 results.push_back(fmt::format(
"std::move(var{})", i+1));
789 results.push_back(fmt::format(
"var{}", i+1));
802 cerr <<
"*****" << endl;
803 if (decl->isDependentType()) {
804 cerr << fmt::format(
"{} is a dependent type", name) << endl;
806 if (
auto spec = dyn_cast<ClassTemplateSpecializationDecl>(decl)) {
807 fprintf(stderr,
"decl is a ClassTemplateSpecializationDecl: %p\n", (
void *)decl);
808 cerr << name << endl;
810 if (
auto spec_tmpl = spec->getSpecializedTemplate()) {
811 fprintf(stderr,
"Specialized template: %p, %s\n", (
void *)spec_tmpl, spec_tmpl->getQualifiedNameAsString().c_str());
814 cerr <<
"no spec tmpl" << endl;
818 if (dyn_cast<ClassTemplatePartialSpecializationDecl>(decl)) {
819 cerr <<
"It is also a partial specialization decl" << endl;
821 cerr <<
"It is NOT a PARTIAL specialization decl" << endl;
826 cerr << name <<
" is not a class template specialization decl" << endl;
828 cerr <<
"*****END" << endl;
int matched_classes_returned
vector< string > types_to_ignore_regex
map< string, int > template_instantiations
bool generate_v8classwrapper_sfinae
static ClassTemplate & get_or_create(const ClassTemplateDecl *decl)
vector< QualType > get_method_param_qual_types(CompilerInstance &compiler_instance, const CXXMethodDecl *method, string const &annotation)
ClassTemplate(const ClassTemplateDecl *decl)
std::string get_include_for_source_location(CompilerInstance &compiler_instance, const SourceLocation &source_location)
std::string get_type_string(QualType qual_type, const std::string &indentation)
static vector< WrappedClass * > wrapped_classes
static FunctionTemplate & get_or_create(const FunctionDecl *decl)
string header_for_every_class_wrapper_file
string get_sfinae_matching_wrapped_classes(const vector< unique_ptr< WrappedClass >> &wrapped_classes)
std::string get_include_for_type_decl(CompilerInstance &compiler_instance, const TypeDecl *type_decl)
bool is_good_record_decl(const CXXRecordDecl *decl)
vector< unique_ptr< FunctionTemplate > > function_templates
const FunctionDecl * decl
vector< string > get_default_argument_values(CompilerInstance &compiler_instance, const CXXMethodDecl *method, const string &annotation="")
std::string js_api_header
std::vector< std::string > used_constructor_names
std::string get_include_string_for_fileid(CompilerInstance &compiler_instance, FileID &file_id)
vector< string > includes_for_every_class_wrapper_file
void print_specialization_info(const CXXRecordDecl *decl)
vector< string > generate_variable_names(vector< QualType > qual_types, bool with_std_move)
vector< std::unique_ptr< ClassTemplate > > class_templates
const ClassTemplateDecl * decl
FunctionTemplate(const FunctionDecl *decl)
bool has(const std::string &target) const
std::string get_source_for_source_range(SourceManager &sm, SourceRange source_range)
vector< string > never_include_for_any_file
std::string get_canonical_name_for_decl(const TypeDecl *decl)
vector< string > base_types_to_ignore
map< string, string > cpp_to_js_type_conversions
std::string join(const T &source, const std::string &between=", ", bool leading_between=false)
bool has_wrapped_class(const CXXRecordDecl *decl)
map< string, string > static_method_renames
void print_vector(const vector< string > &vec, const string &header, const string &indentation, bool ignore_empty)