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(msg: "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::(FunctionDecl *fd) |
146 | { |
147 | QualType return_type = fd->getReturnType(); |
148 | const Type *type = return_type.getTypePtr(); |
149 | |
150 | if (fd->getNumParams() != 2) |
151 | die(msg: "Expecting two arguments" ); |
152 | if (!is_isl_ctx(fd->getParamDecl(0)->getOriginalType())) |
153 | die(msg: "Expecting isl_ctx first argument" ); |
154 | if (!is_isl_type(return_type)) |
155 | die(msg: "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::(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::() |
182 | { |
183 | map<string, isl_class>::iterator ci; |
184 | |
185 | for (ci = classes.begin(); ci != classes.end(); ++ci) |
186 | extract_class_automatic_conversions(clazz: 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(pos: 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(pos: 4); |
302 | fd_name = c->method_name(fd); |
303 | pos = fd_name.find(str: enum_name); |
304 | if (pos == std::string::npos) |
305 | return false; |
306 | prefix = fd_name.substr(pos: 0, n: 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(msg: 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, format: "%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: 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(pos: 0, n: len) == sub) { |
490 | s = s.substr(pos: len + 1, n: s.length() - len - 2); |
491 | if (reversed) |
492 | super.push_back(x: s); |
493 | else |
494 | super.insert(position: super.begin(), x: 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(pos: 0, n: len) == ci->first && |
555 | name[len] == '_') |
556 | best = ci->first; |
557 | } |
558 | |
559 | if (classes.find(x: 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(msg: "No character data" ); |
641 | s = strchr(s: s, c: '('); |
642 | if (!s) |
643 | die(msg: "Cannot find function pointer" ); |
644 | s = strchr(s: s + 1, c: '('); |
645 | if (!s) |
646 | die(msg: "Cannot find function pointer arguments" ); |
647 | end = strchr(s: s + 1, c: ')'); |
648 | if (!end) |
649 | die(msg: "Cannot find end of function pointer arguments" ); |
650 | while (pos-- > 0) { |
651 | s = strchr(s: s + 1, c: ','); |
652 | if (!s || s > end) |
653 | die(msg: "Cannot find function pointer argument" ); |
654 | } |
655 | next = strchr(s: s + 1, c: ','); |
656 | if (next && next < end) |
657 | end = next; |
658 | s = strchr(s: s + 1, c: '_'); |
659 | if (!s || s > end) |
660 | die(msg: "Cannot find function pointer argument annotation" ); |
661 | takes = prefixcmp(s, prefix: "__isl_take" ) == 0; |
662 | keeps = prefixcmp(s, prefix: "__isl_keep" ) == 0; |
663 | if (!takes && !keeps) |
664 | die(msg: "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(pos: 0, n: 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::(QualType type) |
780 | { |
781 | if (type->isPointerType()) |
782 | return type->getPointeeType().getAsString(); |
783 | die(msg: "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::(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(msg: "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(pos: len - suffix_len) == suffix) |
833 | return s.substr(pos: 0, n: 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(s: name, suffix: 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(pos: strlen(s: get_prefix)); |
888 | return base; |
889 | } |
890 | |