1 /* 2 * Copyright 2011,2015 Sven Verdoolaege. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * The views and conclusions contained in the software and documentation 29 * are those of the authors and should not be interpreted as 30 * representing official policies, either expressed or implied, of 31 * Sven Verdoolaege. 32 */ 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <algorithm> 37 #include <iostream> 38 39 #include <clang/AST/Attr.h> 40 #include <clang/Basic/SourceManager.h> 41 42 #include "isl_config.h" 43 #include "extract_interface.h" 44 #include "generator.h" 45 46 const char *isl_class::get_prefix = "get_"; 47 const char *isl_class::set_callback_prefix = "set_"; 48 49 /* Is the first argument an instance of the class? 50 */ 51 bool isl_class::first_arg_matches_class(FunctionDecl *method) const 52 { 53 ParmVarDecl *param; 54 QualType type; 55 56 if (method->getNumParams() < 1) 57 return false; 58 59 param = method->getParamDecl(0); 60 type = param->getOriginalType(); 61 if (!generator::is_isl_type(type)) 62 return false; 63 return generator::extract_type(type) == name; 64 } 65 66 /* Should "method" be considered to be a static method? 67 * That is, is the first argument something other than 68 * an instance of the class? 69 * 70 * If this method was copied from a superclass, then check 71 * whether the method is static with respect to this superclass. 72 */ 73 bool isl_class::is_static(FunctionDecl *method) const 74 { 75 if (copied_from.count(method) != 0) 76 return copied_from.at(method).is_static(method); 77 return !first_arg_matches_class(method); 78 } 79 80 /* Should "method" be considered to be a static method? 81 * That is, is the first argument something other than 82 * an instance of the class? 83 */ 84 bool generator::is_static(const isl_class &clazz, FunctionDecl *method) 85 { 86 return clazz.is_static(method); 87 } 88 89 /* Does "fd" modify an object of "clazz"? 90 * That is, is it an object method that takes the object and 91 * returns (gives) an object of the same type? 92 */ 93 bool generator::is_mutator(const isl_class &clazz, FunctionDecl *fd) 94 { 95 ParmVarDecl *param; 96 QualType type, return_type; 97 98 if (fd->getNumParams() < 1) 99 return false; 100 if (is_static(clazz, fd)) 101 return false; 102 103 if (!gives(fd)) 104 return false; 105 param = fd->getParamDecl(0); 106 if (!takes(param)) 107 return false; 108 type = param->getOriginalType(); 109 return_type = fd->getReturnType(); 110 return return_type == type; 111 } 112 113 /* Find the FunctionDecl with name "name", 114 * returning NULL if there is no such FunctionDecl. 115 * If "required" is set, then error out if no FunctionDecl can be found. 116 */ 117 FunctionDecl *generator::find_by_name(const string &name, bool required) 118 { 119 map<string, FunctionDecl *>::iterator i; 120 121 i = functions_by_name.find(name); 122 if (i != functions_by_name.end()) 123 return i->second; 124 if (required) 125 die("No " + name + " function found"); 126 return NULL; 127 } 128 129 /* List of conversion functions that are used to automatically convert 130 * the second argument of the conversion function to its function result. 131 */ 132 const std::set<std::string> generator::automatic_conversion_functions = { 133 "isl_id_read_from_str", 134 "isl_val_int_from_si", 135 }; 136 137 /* Extract information about the automatic conversion function "fd", 138 * storing the results in this->conversions. 139 * 140 * A function used for automatic conversion has exactly two arguments, 141 * an isl_ctx and a non-isl object, and it returns an isl object. 142 * Store a mapping from the isl object return type 143 * to the non-isl object source type. 144 */ 145 void generator::extract_automatic_conversion(FunctionDecl *fd) 146 { 147 QualType return_type = fd->getReturnType(); 148 const Type *type = return_type.getTypePtr(); 149 150 if (fd->getNumParams() != 2) 151 die("Expecting two arguments"); 152 if (!is_isl_ctx(fd->getParamDecl(0)->getOriginalType())) 153 die("Expecting isl_ctx first argument"); 154 if (!is_isl_type(return_type)) 155 die("Expecting isl object return type"); 156 conversions[type] = fd->getParamDecl(1); 157 } 158 159 /* Extract information about all automatic conversion functions 160 * for the given class, storing the results in this->conversions. 161 * 162 * In particular, look through all exported constructors for the class and 163 * check if any of them is explicitly marked as a conversion function. 164 */ 165 void generator::extract_class_automatic_conversions(const isl_class &clazz) 166 { 167 const function_set &constructors = clazz.constructors; 168 function_set::iterator fi; 169 170 for (fi = constructors.begin(); fi != constructors.end(); ++fi) { 171 FunctionDecl *fd = *fi; 172 string name = fd->getName().str(); 173 if (automatic_conversion_functions.count(name) != 0) 174 extract_automatic_conversion(fd); 175 } 176 } 177 178 /* Extract information about all automatic conversion functions, 179 * storing the results in this->conversions. 180 */ 181 void generator::extract_automatic_conversions() 182 { 183 map<string, isl_class>::iterator ci; 184 185 for (ci = classes.begin(); ci != classes.end(); ++ci) 186 extract_class_automatic_conversions(ci->second); 187 } 188 189 /* Add a subclass derived from "decl" called "sub_name" to the set of classes, 190 * keeping track of the _to_str, _copy and _free functions, if any, separately. 191 * "sub_name" is either the name of the class itself or 192 * the name of a type based subclass. 193 * If the class is a proper subclass, then "super_name" is the name 194 * of its immediate superclass. 195 */ 196 void generator::add_subclass(RecordDecl *decl, const string &super_name, 197 const string &sub_name) 198 { 199 string name = decl->getName().str(); 200 201 classes[sub_name].name = name; 202 classes[sub_name].superclass_name = super_name; 203 classes[sub_name].subclass_name = sub_name; 204 classes[sub_name].type = decl; 205 classes[sub_name].fn_to_str = find_by_name(name + "_to_str", false); 206 classes[sub_name].fn_copy = find_by_name(name + "_copy", true); 207 classes[sub_name].fn_free = find_by_name(name + "_free", true); 208 } 209 210 /* Add a class derived from "decl" to the set of classes, 211 * keeping track of the _to_str, _copy and _free functions, if any, separately. 212 */ 213 void generator::add_class(RecordDecl *decl) 214 { 215 return add_subclass(decl, "", decl->getName().str()); 216 } 217 218 /* Given a function "fn_type" that returns the subclass type 219 * of a C object, create subclasses for each of the (non-negative) 220 * return values. 221 * 222 * The function "fn_type" is also stored in the superclass, 223 * along with all pairs of type values and subclass names. 224 */ 225 void generator::add_type_subclasses(FunctionDecl *fn_type) 226 { 227 QualType return_type = fn_type->getReturnType(); 228 const EnumType *enum_type = return_type->getAs<EnumType>(); 229 EnumDecl *decl = enum_type->getDecl(); 230 isl_class *c = method2class(fn_type); 231 DeclContext::decl_iterator i; 232 233 c->fn_type = fn_type; 234 for (i = decl->decls_begin(); i != decl->decls_end(); ++i) { 235 EnumConstantDecl *ecd = dyn_cast<EnumConstantDecl>(*i); 236 int val = (int) ecd->getInitVal().getSExtValue(); 237 string name = ecd->getNameAsString(); 238 239 if (val < 0) 240 continue; 241 c->type_subclasses[val] = name; 242 add_subclass(c->type, c->subclass_name, name); 243 } 244 } 245 246 /* Add information about the enum values in "decl", set by "fd", 247 * to c->set_enums. "prefix" is the prefix of the generated method names. 248 * In particular, it has the name of the enum type removed. 249 * 250 * In particular, for each non-negative enum value, keep track of 251 * the value, the name and the corresponding method name. 252 */ 253 static void add_set_enum(isl_class *c, const string &prefix, EnumDecl *decl, 254 FunctionDecl *fd) 255 { 256 DeclContext::decl_iterator i; 257 258 for (i = decl->decls_begin(); i != decl->decls_end(); ++i) { 259 EnumConstantDecl *ecd = dyn_cast<EnumConstantDecl>(*i); 260 int val = (int) ecd->getInitVal().getSExtValue(); 261 string name = ecd->getNameAsString(); 262 string method_name; 263 264 if (val < 0) 265 continue; 266 method_name = prefix + name.substr(4); 267 c->set_enums[fd].push_back(set_enum(val, name, method_name)); 268 } 269 } 270 271 /* Check if "fd" sets an enum value and, if so, add information 272 * about the enum values to c->set_enums. 273 * 274 * A function is considered to set an enum value if: 275 * - the function returns an object of the same type 276 * - the last argument is of type enum 277 * - the name of the function ends with the name of the enum 278 */ 279 static bool handled_sets_enum(isl_class *c, FunctionDecl *fd) 280 { 281 unsigned n; 282 ParmVarDecl *param; 283 const EnumType *enum_type; 284 EnumDecl *decl; 285 string enum_name; 286 string fd_name; 287 string prefix; 288 size_t pos; 289 290 if (!generator::is_mutator(*c, fd)) 291 return false; 292 n = fd->getNumParams(); 293 if (n < 2) 294 return false; 295 param = fd->getParamDecl(n - 1); 296 enum_type = param->getType()->getAs<EnumType>(); 297 if (!enum_type) 298 return false; 299 decl = enum_type->getDecl(); 300 enum_name = decl->getName().str(); 301 enum_name = enum_name.substr(4); 302 fd_name = c->method_name(fd); 303 pos = fd_name.find(enum_name); 304 if (pos == std::string::npos) 305 return false; 306 prefix = fd_name.substr(0, pos); 307 308 add_set_enum(c, prefix, decl, fd); 309 310 return true; 311 } 312 313 /* Return the callback argument of a function setting 314 * a persistent callback. 315 * This callback is in the second argument (position 1). 316 */ 317 ParmVarDecl *generator::persistent_callback_arg(FunctionDecl *fd) 318 { 319 return fd->getParamDecl(1); 320 } 321 322 /* Does the given function set a persistent callback? 323 * The following heuristics are used to determine this property: 324 * - the function returns an object of the same type 325 * - its name starts with "set_" 326 * - it has exactly three arguments 327 * - the second (position 1) of which is a callback 328 */ 329 static bool sets_persistent_callback(isl_class *c, FunctionDecl *fd) 330 { 331 ParmVarDecl *param; 332 333 if (!generator::is_mutator(*c, fd)) 334 return false; 335 if (fd->getNumParams() != 3) 336 return false; 337 param = generator::persistent_callback_arg(fd); 338 if (!generator::is_callback(param->getType())) 339 return false; 340 return prefixcmp(c->method_name(fd).c_str(), 341 c->set_callback_prefix) == 0; 342 } 343 344 /* Does this function take any enum arguments? 345 */ 346 static bool takes_enums(FunctionDecl *fd) 347 { 348 unsigned n; 349 350 n = fd->getNumParams(); 351 for (unsigned i = 0; i < n; ++i) { 352 ParmVarDecl *param = fd->getParamDecl(i); 353 if (param->getType()->getAs<EnumType>()) 354 return true; 355 } 356 return false; 357 } 358 359 /* Sorting function that places declaration of functions 360 * with a shorter name first. 361 */ 362 static bool less_name(const FunctionDecl *a, const FunctionDecl *b) 363 { 364 return a->getName().size() < b->getName().size(); 365 } 366 367 /* Collect all functions that belong to a certain type, separating 368 * constructors from methods that set an enum value, 369 * methods that set a persistent callback and 370 * from regular methods, while keeping track of the _to_str, 371 * _copy and _free functions, if any, separately. 372 * Methods that accept any enum arguments that are not specifically handled 373 * are not supported. 374 * If there are any overloaded 375 * functions, then they are grouped based on their name after removing the 376 * argument type suffix. 377 * Check for functions that describe subclasses before considering 378 * any other functions in order to be able to detect those other 379 * functions as belonging to the subclasses. 380 * Sort the names of the functions based on their lengths 381 * to ensure that nested subclasses are handled later. 382 * 383 * Also extract information about automatic conversion functions. 384 */ 385 generator::generator(SourceManager &SM, set<RecordDecl *> &exported_types, 386 set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions) : 387 SM(SM) 388 { 389 set<FunctionDecl *>::iterator in; 390 set<RecordDecl *>::iterator it; 391 vector<FunctionDecl *> type_subclasses; 392 vector<FunctionDecl *>::iterator iv; 393 394 for (in = functions.begin(); in != functions.end(); ++in) { 395 FunctionDecl *decl = *in; 396 functions_by_name[decl->getName().str()] = decl; 397 } 398 399 for (it = exported_types.begin(); it != exported_types.end(); ++it) 400 add_class(*it); 401 402 for (in = exported_functions.begin(); in != exported_functions.end(); 403 ++in) { 404 if (is_subclass(*in)) 405 type_subclasses.push_back(*in); 406 } 407 std::sort(type_subclasses.begin(), type_subclasses.end(), &less_name); 408 for (iv = type_subclasses.begin(); iv != type_subclasses.end(); ++iv) { 409 add_type_subclasses(*iv); 410 } 411 412 for (in = exported_functions.begin(); in != exported_functions.end(); 413 ++in) { 414 FunctionDecl *method = *in; 415 isl_class *c; 416 417 if (is_subclass(method)) 418 continue; 419 420 c = method2class(method); 421 if (!c) 422 continue; 423 if (is_constructor(method)) { 424 c->constructors.insert(method); 425 } else if (handled_sets_enum(c, method)) { 426 } else if (sets_persistent_callback(c, method)) { 427 c->persistent_callbacks.insert(method); 428 } else if (takes_enums(method)) { 429 std::string name = method->getName().str(); 430 die(name + " has unhandled enum argument"); 431 } else { 432 string name = c->method_name(method); 433 c->methods[name].insert(method); 434 } 435 } 436 437 extract_automatic_conversions(); 438 } 439 440 /* Print error message "msg" and abort. 441 */ 442 void generator::die(const char *msg) 443 { 444 fprintf(stderr, "%s\n", msg); 445 abort(); 446 } 447 448 /* Print error message "msg" and abort. 449 */ 450 void generator::die(string msg) 451 { 452 die(msg.c_str()); 453 } 454 455 /* Return a sequence of the types of which the given type declaration is 456 * marked as being a subtype. 457 * The order of the types is the opposite of the order in which they 458 * appear in the source. In particular, the first annotation 459 * is the one that is closest to the annotated type and the corresponding 460 * type is then also the first that will appear in the sequence of types. 461 * This is also the order in which the annotations appear 462 * in the AttrVec returned by Decl::getAttrs() in older versions of clang. 463 * In newer versions of clang, the order is that in which 464 * the attribute appears in the source. 465 * Use the position of the "isl_export" attribute to determine 466 * whether this is an old (with reversed order) or a new version. 467 * The "isl_export" attribute is automatically added 468 * after each "isl_subclass" attribute. If it appears in the list before 469 * any "isl_subclass" is encountered, then this must be a reversed list. 470 */ 471 std::vector<string> generator::find_superclasses(Decl *decl) 472 { 473 vector<string> super; 474 bool reversed = false; 475 476 if (!decl->hasAttrs()) 477 return super; 478 479 string sub = "isl_subclass"; 480 size_t len = sub.length(); 481 AttrVec attrs = decl->getAttrs(); 482 for (AttrVec::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { 483 const AnnotateAttr *ann = dyn_cast<AnnotateAttr>(*i); 484 if (!ann) 485 continue; 486 string s = ann->getAnnotation().str(); 487 if (s == "isl_export" && super.size() == 0) 488 reversed = true; 489 if (s.substr(0, len) == sub) { 490 s = s.substr(len + 1, s.length() - len - 2); 491 if (reversed) 492 super.push_back(s); 493 else 494 super.insert(super.begin(), s); 495 } 496 } 497 498 return super; 499 } 500 501 /* Is "decl" marked as describing subclasses? 502 */ 503 bool generator::is_subclass(FunctionDecl *decl) 504 { 505 return find_superclasses(decl).size() > 0; 506 } 507 508 /* Is decl marked as being part of an overloaded method? 509 */ 510 bool generator::is_overload(Decl *decl) 511 { 512 return has_annotation(decl, "isl_overload"); 513 } 514 515 /* Is decl marked as a constructor? 516 */ 517 bool generator::is_constructor(Decl *decl) 518 { 519 return has_annotation(decl, "isl_constructor"); 520 } 521 522 /* Is decl marked as consuming a reference? 523 */ 524 bool generator::takes(Decl *decl) 525 { 526 return has_annotation(decl, "isl_take"); 527 } 528 529 /* Is decl marked as preserving a reference? 530 */ 531 bool generator::keeps(Decl *decl) 532 { 533 return has_annotation(decl, "isl_keep"); 534 } 535 536 /* Is decl marked as returning a reference that is required to be freed. 537 */ 538 bool generator::gives(Decl *decl) 539 { 540 return has_annotation(decl, "isl_give"); 541 } 542 543 /* Return the class that has a name that best matches the initial part 544 * of the name of function "fd" or NULL if no such class could be found. 545 */ 546 isl_class *generator::method2class(FunctionDecl *fd) 547 { 548 string best; 549 map<string, isl_class>::iterator ci; 550 string name = fd->getNameAsString(); 551 552 for (ci = classes.begin(); ci != classes.end(); ++ci) { 553 size_t len = ci->first.length(); 554 if (len > best.length() && name.substr(0, len) == ci->first && 555 name[len] == '_') 556 best = ci->first; 557 } 558 559 if (classes.find(best) == classes.end()) { 560 cerr << "Unable to find class of " << name << endl; 561 return NULL; 562 } 563 564 return &classes[best]; 565 } 566 567 /* Is "type" the type "isl_ctx *"? 568 */ 569 bool generator::is_isl_ctx(QualType type) 570 { 571 if (!type->isPointerType()) 572 return false; 573 type = type->getPointeeType(); 574 if (type.getAsString() != "isl_ctx") 575 return false; 576 577 return true; 578 } 579 580 /* Is the first argument of "fd" of type "isl_ctx *"? 581 */ 582 bool generator::first_arg_is_isl_ctx(FunctionDecl *fd) 583 { 584 ParmVarDecl *param; 585 586 if (fd->getNumParams() < 1) 587 return false; 588 589 param = fd->getParamDecl(0); 590 return is_isl_ctx(param->getOriginalType()); 591 } 592 593 namespace { 594 595 struct ClangAPI { 596 /* Return the first location in the range returned by 597 * clang::SourceManager::getImmediateExpansionRange. 598 * Older versions of clang return a pair of SourceLocation objects. 599 * More recent versions return a CharSourceRange. 600 */ 601 static SourceLocation range_begin( 602 const std::pair<SourceLocation,SourceLocation> &p) { 603 return p.first; 604 } 605 static SourceLocation range_begin(const CharSourceRange &range) { 606 return range.getBegin(); 607 } 608 }; 609 610 } 611 612 /* Does the callback argument "param" take its argument at position "pos"? 613 * 614 * The memory management annotations of arguments to function pointers 615 * are not recorded by clang, so the information cannot be extracted 616 * from the type of "param". 617 * Instead, go to the location in the source where the callback argument 618 * is declared, look for the right argument of the callback itself and 619 * then check if it has an "__isl_take" memory management annotation. 620 * 621 * If the return value of the function has a memory management annotation, 622 * then the spelling of "param" will point to the spelling 623 * of this memory management annotation. Since the macro is defined 624 * on the command line (in main), this location does not have a file entry. 625 * In this case, move up one level in the macro expansion to the location 626 * where the memory management annotation is used. 627 */ 628 bool generator::callback_takes_argument(ParmVarDecl *param, 629 int pos) 630 { 631 SourceLocation loc; 632 const char *s, *end, *next; 633 bool takes, keeps; 634 635 loc = param->getSourceRange().getBegin(); 636 if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(loc)))) 637 loc = ClangAPI::range_begin(SM.getImmediateExpansionRange(loc)); 638 s = SM.getCharacterData(loc); 639 if (!s) 640 die("No character data"); 641 s = strchr(s, '('); 642 if (!s) 643 die("Cannot find function pointer"); 644 s = strchr(s + 1, '('); 645 if (!s) 646 die("Cannot find function pointer arguments"); 647 end = strchr(s + 1, ')'); 648 if (!end) 649 die("Cannot find end of function pointer arguments"); 650 while (pos-- > 0) { 651 s = strchr(s + 1, ','); 652 if (!s || s > end) 653 die("Cannot find function pointer argument"); 654 } 655 next = strchr(s + 1, ','); 656 if (next && next < end) 657 end = next; 658 s = strchr(s + 1, '_'); 659 if (!s || s > end) 660 die("Cannot find function pointer argument annotation"); 661 takes = prefixcmp(s, "__isl_take") == 0; 662 keeps = prefixcmp(s, "__isl_keep") == 0; 663 if (!takes && !keeps) 664 die("Cannot find function pointer argument annotation"); 665 666 return takes; 667 } 668 669 /* Is "type" that of a pointer to an isl_* structure? 670 */ 671 bool generator::is_isl_type(QualType type) 672 { 673 if (type->isPointerType()) { 674 string s; 675 676 type = type->getPointeeType(); 677 if (type->isFunctionType()) 678 return false; 679 s = type.getAsString(); 680 return s.substr(0, 4) == "isl_"; 681 } 682 683 return false; 684 } 685 686 /* Is "type" one of the integral types with a negative value 687 * indicating an error condition? 688 */ 689 bool generator::is_isl_neg_error(QualType type) 690 { 691 return is_isl_bool(type) || is_isl_stat(type) || is_isl_size(type); 692 } 693 694 /* Is "type" the primitive type with the given name? 695 */ 696 static bool is_isl_primitive(QualType type, const char *name) 697 { 698 string s; 699 700 if (type->isPointerType()) 701 return false; 702 703 s = type.getAsString(); 704 return s == name; 705 } 706 707 /* Is "type" the type isl_bool? 708 */ 709 bool generator::is_isl_bool(QualType type) 710 { 711 return is_isl_primitive(type, "isl_bool"); 712 } 713 714 /* Is "type" the type isl_stat? 715 */ 716 bool generator::is_isl_stat(QualType type) 717 { 718 return is_isl_primitive(type, "isl_stat"); 719 } 720 721 /* Is "type" the type isl_size? 722 */ 723 bool generator::is_isl_size(QualType type) 724 { 725 return is_isl_primitive(type, "isl_size"); 726 } 727 728 /* Is "type" that of a pointer to a function? 729 */ 730 bool generator::is_callback(QualType type) 731 { 732 if (!type->isPointerType()) 733 return false; 734 type = type->getPointeeType(); 735 return type->isFunctionType(); 736 } 737 738 /* Is the parameter at position "i" of "fd" a pointer to a function? 739 */ 740 bool generator::is_callback_arg(FunctionDecl *fd, int i) 741 { 742 ParmVarDecl *param = fd->getParamDecl(i); 743 QualType type = param->getOriginalType(); 744 745 return is_callback(type); 746 } 747 748 /* Is "type" that of "char *" of "const char *"? 749 */ 750 bool generator::is_string(QualType type) 751 { 752 if (type->isPointerType()) { 753 string s = type->getPointeeType().getAsString(); 754 return s == "const char" || s == "char"; 755 } 756 757 return false; 758 } 759 760 /* Is "type" that of "long"? 761 */ 762 bool generator::is_long(QualType type) 763 { 764 const BuiltinType *builtin = type->getAs<BuiltinType>(); 765 return builtin && builtin->getKind() == BuiltinType::Long; 766 } 767 768 /* Is "type" that of "unsigned int"? 769 */ 770 static bool is_unsigned_int(QualType type) 771 { 772 const BuiltinType *builtin = type->getAs<BuiltinType>(); 773 return builtin && builtin->getKind() == BuiltinType::UInt; 774 } 775 776 /* Return the name of the type that "type" points to. 777 * The input "type" is assumed to be a pointer type. 778 */ 779 string generator::extract_type(QualType type) 780 { 781 if (type->isPointerType()) 782 return type->getPointeeType().getAsString(); 783 die("Cannot extract type from non-pointer type"); 784 } 785 786 /* Given the type of a function pointer, return the corresponding 787 * function prototype. 788 */ 789 const FunctionProtoType *generator::extract_prototype(QualType type) 790 { 791 return type->getPointeeType()->getAs<FunctionProtoType>(); 792 } 793 794 /* Given the type of a function pointer, return the number of arguments 795 * of the corresponding function prototype. 796 */ 797 int generator::prototype_n_args(QualType type) 798 { 799 return extract_prototype(type)->getNumArgs(); 800 } 801 802 /* Return the function name suffix for the type of "param". 803 * 804 * If the type of "param" is an isl object type, 805 * then the suffix is the name of the type with the "isl" prefix removed, 806 * but keeping the "_". 807 * If the type is an unsigned integer, then the type suffix is "_ui". 808 */ 809 static std::string type_suffix(ParmVarDecl *param) 810 { 811 QualType type; 812 813 type = param->getOriginalType(); 814 if (generator::is_isl_type(type)) 815 return generator::extract_type(type).substr(3); 816 else if (is_unsigned_int(type)) 817 return "_ui"; 818 generator::die("Unsupported type suffix"); 819 } 820 821 /* If "suffix" is a suffix of "s", then return "s" with the suffix removed. 822 * Otherwise, simply return "s". 823 */ 824 std::string generator::drop_suffix(const std::string &s, 825 const std::string &suffix) 826 { 827 size_t len, suffix_len; 828 829 len = s.length(); 830 suffix_len = suffix.length(); 831 832 if (len >= suffix_len && s.substr(len - suffix_len) == suffix) 833 return s.substr(0, len - suffix_len); 834 else 835 return s; 836 } 837 838 /* If "method" is overloaded, then return its name with the suffixes 839 * corresponding to the types of the final arguments removed. 840 * Otherwise, simply return the name of the function. 841 * Start from the final argument and keep removing suffixes 842 * matching arguments, independently of whether previously considered 843 * arguments matched. 844 */ 845 string isl_class::name_without_type_suffixes(FunctionDecl *method) 846 { 847 int num_params; 848 string name; 849 850 name = method->getName().str(); 851 if (!generator::is_overload(method)) 852 return name; 853 854 num_params = method->getNumParams(); 855 for (int i = num_params - 1; i >= 0; --i) { 856 ParmVarDecl *param; 857 string type; 858 859 param = method->getParamDecl(i); 860 type = type_suffix(param); 861 862 name = generator::drop_suffix(name, type); 863 } 864 865 return name; 866 } 867 868 /* Is function "fd" with the given name a "get" method? 869 * 870 * A "get" method is an instance method 871 * with a name that starts with the get method prefix. 872 */ 873 bool isl_class::is_get_method_name(FunctionDecl *fd, const string &name) const 874 { 875 return !is_static(fd) && prefixcmp(name.c_str(), get_prefix) == 0; 876 } 877 878 /* Extract the method name corresponding to "fd". 879 * 880 * If "fd" is a "get" method, then drop the "get" method prefix. 881 */ 882 string isl_class::method_name(FunctionDecl *fd) const 883 { 884 string base = base_method_name(fd); 885 886 if (is_get_method_name(fd, base)) 887 return base.substr(strlen(get_prefix)); 888 return base; 889 } 890