]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
Release 2.0.16
[gob-dx.git] / src / checks.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999-2000 the Free Software Foundation.
3  * Copyright (C) 2000 Eazel, Inc.
4  * Copyright (C) 2001-2004 George Lebl
5  *
6  * Author: George Lebl
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the  Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21  * USA.
22  */
23
24 #include "config.h"
25 #include <string.h>
26 #include <stdio.h>
27 #include <glib.h>
28
29 #include "treefuncs.h"
30 #include "main.h"
31 #include "util.h"
32
33 #include "checks.h"
34
35 static void
36 check_duplicate (Class *c, Node *node, const char *id, int line_no)
37 {
38         GList *li;
39         for (li = c->nodes; li != NULL; li = li->next) {
40                 Node *n = li->data;
41                 const char *nid;
42                 int nline_no;
43                 if(n->type == METHOD_NODE) {
44                         Method *m = (Method *)n;
45
46                         /* override methods are checked separately */
47                         if(m->method == OVERRIDE_METHOD)
48                                 continue;
49
50                         nid = m->id;
51                         nline_no = m->line_no;
52                 } else if(n->type == VARIABLE_NODE) {
53                         Variable *v = (Variable *)n;
54                         nid = v->id;
55                         nline_no = v->line_no;
56                 } else
57                         continue;
58                 if(n == node ||
59                    line_no > nline_no ||
60                    n->type != node->type ||
61                    strcmp(nid, id) != 0)
62                         continue;
63
64                 error_printf (GOB_ERROR, nline_no,
65                               "symbol '%s' redefined, "
66                               "first defined on line %d",
67                               id, line_no);
68         }
69 }
70
71 void
72 check_duplicate_symbols (Class *c)
73 {
74         GList *li;
75         for (li = c->nodes; li != NULL; li = li->next) {
76                 Node *n = li->data;
77
78                 if (n->type == METHOD_NODE) {
79                         Method *m = (Method *)n;
80                         /* override methods are checked separately */
81                         if (m->method != OVERRIDE_METHOD) {
82                                 check_duplicate (c, n, m->id, m->line_no);
83                         }
84                 } else if (n->type == VARIABLE_NODE) {
85                         Variable *v = (Variable *)n;
86                         check_duplicate (c, n, v->id, v->line_no);
87                 }
88         }
89 }
90
91 static void
92 check_duplicate_override (Class *c, Method *method)
93 {
94         GList *li;
95         for (li = c->nodes; li != NULL; li = li->next) {
96                 Node *n = li->data;
97                 Method *m = (Method *)n;
98                 if(n->type != METHOD_NODE ||
99                    m->method != OVERRIDE_METHOD)
100                         continue;
101
102                 if(method == m ||
103                    method->line_no > m->line_no ||
104                    strcmp(m->id, method->id) != 0 ||
105                    strcmp(m->otype, method->otype) != 0)
106                         continue;
107                 error_printf(GOB_ERROR, m->line_no,
108                              "override '%s(%s)' redefined, "
109                              "first defined on line %d",
110                              m->id, m->otype, method->line_no);
111         }
112 }
113
114 void
115 check_duplicate_overrides(Class *c)
116 {
117         GList *li;
118         for(li = c->nodes; li != NULL; li = li->next) {
119                 Node *n = li->data;
120                 Method *m = (Method *)n;
121                 if(n->type != METHOD_NODE ||
122                    m->method != OVERRIDE_METHOD)
123                         continue;
124                 check_duplicate_override(c, m);
125         }
126 }
127
128 void
129 check_bad_symbols(Class *c)
130 {
131         GList *li;
132         for(li = c->nodes; li != NULL; li = li->next) {
133                 Node *n = li->data;
134                 if(n->type == METHOD_NODE) {
135                         Method *m = (Method *)n;
136                         if((m->method == SIGNAL_LAST_METHOD ||
137                             m->method == SIGNAL_FIRST_METHOD ||
138                             m->method == VIRTUAL_METHOD) &&
139                            (strcmp(m->id, "_epv")==0 ||
140                             strcmp(m->id, "__parent__")==0 ||
141                             strcmp(m->id, "___parent__")==0)) {
142                                 error_printf(GOB_ERROR, m->line_no,
143                                              "'%s' not allowed as an "
144                                              "identifier of signal "
145                                              "or virtual methods",
146                                              m->id);
147                         }
148                         if(m->method != INIT_METHOD &&
149                            m->method != CLASS_INIT_METHOD &&
150                            (strcmp(m->id, "init")==0 ||
151                             strcmp(m->id, "class_init")==0)) {
152                                 error_print(GOB_ERROR, m->line_no,
153                                             "init, or class_init not "
154                                             "allowed as an "
155                                             "identifier of non-"
156                                             "constructor methods");
157                         }
158                 } else if(n->type == VARIABLE_NODE) {
159                         Variable *v = (Variable *)n;
160                         if(strcmp(v->id, "_priv")==0 ||
161                            strcmp(v->id, "__parent__")==0) {
162                                 error_printf(GOB_ERROR, v->line_no,
163                                              "'%s' not allowed as a "
164                                              "data member name", v->id);
165                         }
166                 }
167         }
168 }
169
170 static void
171 check_duplicate_named (Class *c, Node *node, const char *id, int line_no)
172 {
173         GList *li;
174         for (li = c->nodes; li != NULL; li = li->next) {
175                 Node *n = li->data;
176                 const char *nid;
177                 int nline_no;
178                 if (n->type == METHOD_NODE) {
179                         Method *m = (Method *)n;
180                         if (m->method == SIGNAL_LAST_METHOD ||
181                             m->method == SIGNAL_FIRST_METHOD) {
182                                 nid = m->id;
183                                 nline_no = m->line_no;
184                         } else {
185                                 continue;
186                         }
187                 } else if (n->type == ARGUMENT_NODE) {
188                         Argument *a = (Argument *)n;
189                         nid = a->name;
190                         nline_no = a->line_no;
191                 } else if (n->type == PROPERTY_NODE) {
192                         Property *p = (Property *)n;
193                         nid = p->name;
194                         nline_no = p->line_no;
195                 } else {
196                         continue;
197                 }
198                 if (n == node ||
199                     line_no >= nline_no ||
200                     g_strcasecmp (nid, id) != 0)
201                         continue;
202                 error_printf (GOB_ERROR, nline_no,
203                               "named symbol (argument or signal) '%s' "
204                               "redefined, first defined on line %d "
205                               "(case insensitive)",
206                               id, line_no);
207         }
208 }
209
210 void
211 check_duplicate_signals_args (Class *c)
212 {
213         GList *li;
214         for (li = c->nodes; li != NULL; li = li->next) {
215                 Node *n = li->data;
216                 if (n->type == METHOD_NODE) {
217                         Method *m = (Method *)n;
218                         if(m->method == SIGNAL_LAST_METHOD ||
219                            m->method == SIGNAL_FIRST_METHOD)
220                                 check_duplicate_named (c, n, m->id,
221                                                        m->line_no);
222                 } else if (n->type == PROPERTY_NODE) {
223                         Property *p = (Property *)n;
224                         check_duplicate_named (c, n, p->name, p->line_no);
225                 } else if (n->type == ARGUMENT_NODE) {
226                         Argument *a = (Argument *)n;
227                         check_duplicate_named (c, n, a->name, a->line_no);
228                 }
229         }
230 }
231
232 void
233 check_public_new(Class *c)
234 {
235         GList *li;
236         for(li = c->nodes; li != NULL; li = li->next) {
237                 Node *n = li->data;
238                 if(n->type == METHOD_NODE) {
239                         Method *m = (Method *)n;
240                         if((strcmp(m->id, "new")==0) &&
241                            (m->method != REGULAR_METHOD ||
242                             m->scope != PUBLIC_SCOPE))
243                                 error_print(GOB_WARN, m->line_no,
244                                             "'new' should be a regular\n"
245                                             "public method");
246                 }
247         }
248 }
249
250 void
251 check_vararg(Class *c)
252 {
253         GList *li;
254         for(li = c->nodes; li != NULL; li = li->next) {
255                 Node *n = li->data;
256                 if(n->type == METHOD_NODE) {
257                         Method *m = (Method *)n;
258                         if( ! m->vararg)
259                                 continue;
260                         if(m->method == OVERRIDE_METHOD ||
261                            m->method == SIGNAL_LAST_METHOD ||
262                            m->method == SIGNAL_FIRST_METHOD ||
263                            m->method == VIRTUAL_METHOD) {
264                                 error_print(GOB_ERROR, m->line_no,
265                                             "signals, overrides and virtuals, "
266                                             "can't have variable argument "
267                                             "lists");
268                         }
269                 }
270         }
271 }
272
273 void
274 check_firstarg(Class *c)
275 {
276         GList *li;
277         for(li = c->nodes; li != NULL; li = li->next) {
278                 Node *n = li->data;
279                 if(n->type == METHOD_NODE) {
280                         Method *m = (Method *)n;
281                         if(m->args)
282                                 continue;
283                         if(m->method == OVERRIDE_METHOD ||
284                            m->method == SIGNAL_LAST_METHOD ||
285                            m->method == SIGNAL_FIRST_METHOD ||
286                            m->method == VIRTUAL_METHOD) {
287                                 error_print(GOB_ERROR, m->line_no,
288                                             "signals, overrides and virtuals, "
289                                             "can't have no arguments");
290                         }
291                 }
292         }
293 }
294
295 void
296 check_nonvoidempty(Class *c)
297 {
298         GList *li;
299         for(li = c->nodes; li != NULL; li = li->next) {
300                 Node *n = li->data;
301                 if(n->type == METHOD_NODE) {
302                         Method *m = (Method *)n;
303                         if(m->method != REGULAR_METHOD)
304                                 continue;
305                         if(!(strcmp(m->mtype->name, "void")==0 &&
306                              m->mtype->pointer == NULL) &&
307                            !m->cbuf) {
308                                 error_print(GOB_WARN, m->line_no,
309                                             "non-void empty method found, "
310                                             "regular non-void function should "
311                                             "not be empty.");
312                                 /* add a body here, so that the user will also
313                                    get a warning from gcc, and so that it will
314                                    at least point him to the prototype of the
315                                    function in the .gob file */
316                                 m->cbuf = g_strdup("/*empty*/");
317                                 m->ccode_line = m->line_no;
318                         }
319                 }
320         }
321 }
322
323 void
324 check_signal_args (Class *c)
325 {
326         GList *li;
327         for (li = c->nodes; li != NULL; li = li->next) {
328                 Node *n = li->data;
329                 if(n->type == METHOD_NODE) {
330                         Method *m = (Method *)n;
331                         GList *l;
332                         if(m->method != SIGNAL_LAST_METHOD &&
333                            m->method != SIGNAL_FIRST_METHOD)
334                                 continue;
335
336                         for (l = m->gtktypes; l != NULL; l = l->next) {
337                                 if (strcmp (l->data, "BOXED") == 0) {
338                                         error_printf (GOB_ERROR, m->line_no,
339                                                       "BOXED not allowed as "
340                                                       "a signal argument, use "
341                                                       "POINTER, or BOXED_*");
342                                         continue;
343                                 } else if (strcmp (l->data, "FLAGS") == 0) {
344                                         error_printf (GOB_ERROR, m->line_no,
345                                                       "FLAGS not allowed as "
346                                                       "a signal argument, use "
347                                                       "UINT");
348                                         continue;
349                                 }
350                                 if (get_cast (l->data, FALSE))
351                                         continue;
352                                 error_printf (GOB_ERROR, m->line_no,
353                                               "Unknown GTK+ type '%s' "
354                                               "among signal types",
355                                               (char *)l->data);
356                         }
357                 }
358         }
359 }
360
361 void
362 check_argument_types (Class *c)
363 {
364         GList *li;
365         for (li = c->nodes; li != NULL; li = li->next) {
366                 Node *n = li->data;
367                 if(n->type == ARGUMENT_NODE) {
368                         Argument *a = (Argument *)n;
369                         if(get_cast(a->gtktype, FALSE))
370                                 continue;
371                         error_printf(GOB_ERROR, a->line_no,
372                                      "Unknown GLib type '%s' "
373                                      "as argument type",
374                                      a->gtktype);
375                 }
376         }
377 }
378
379 void
380 check_property_types (Class *c)
381 {
382         GList *li;
383         for (li = c->nodes; li != NULL; li = li->next) {
384                 Node *n = li->data;
385                 if (n->type == PROPERTY_NODE) {
386                         Property *p = (Property *)n;
387                         if (get_cast (p->gtktype, FALSE))
388                                 continue;
389                         error_printf (GOB_ERROR, p->line_no,
390                                       "Unknown GLib type '%s' "
391                                       "as property type",
392                                       p->gtktype);
393                 }
394         }
395 }
396
397 static void
398 check_func_arg_check_func_arg(Method *m, FuncArg *fa)
399 {
400         GList *li;
401         char *s;
402
403         if( ! fa->checks)
404                 return;
405
406         if(strcmp(fa->atype->name, "void") == 0 &&
407            fa->atype->pointer == NULL) {
408                 error_print(GOB_ERROR, m->line_no,
409                             "Running checks on a void function argument");
410                 return;
411         }
412         
413         for(li = fa->checks; li; li = li->next) {
414                 Check *ch = li->data;
415                 if(ch->chtype == TYPE_CHECK) {
416                         char *p;
417                         gboolean got_type = FALSE;
418                         s = g_strdup(fa->atype->name);
419                         p = strtok(s, " ");
420                         if( ! p) {
421                                 g_free(s);
422                                 goto type_check_error;
423                         }
424                         while(p) {
425                                 if(strcmp(p, "const") != 0) {
426                                         if(got_type) {
427                                                 g_free(s);
428                                                 goto type_check_error;
429                                         }
430                                         got_type = TRUE;
431                                 }
432                                 p = strtok(NULL, " ");
433                         }
434                         g_free(s);
435                         if( ! got_type)
436                                 goto type_check_error;
437
438                         if(fa->atype->pointer == NULL ||
439                            (strcmp(fa->atype->pointer, "*") != 0 &&
440                             strcmp(fa->atype->pointer, "* const") != 0 &&
441                             strcmp(fa->atype->pointer, "const *") != 0))
442                                 goto type_check_error;
443                 }
444         }
445         return;
446
447 type_check_error:
448         if(fa->atype->pointer)
449                 error_printf(GOB_ERROR, m->line_no,
450                              "Cannot check the type of '%s %s'",
451                              fa->atype->name, fa->atype->pointer);
452         else
453                 error_printf(GOB_ERROR, m->line_no,
454                              "Cannot check the type of '%s'",
455                              fa->atype->name);
456 }
457
458 static void
459 check_func_arg_check_method(Method *m)
460 {
461         GList *li;
462         for(li = m->args; li; li = li->next) {
463                 FuncArg *fa = li->data;
464                 check_func_arg_check_func_arg(m, fa);
465         }
466 }
467
468 void
469 check_func_arg_checks(Class *c)
470 {
471         GList *li;
472         for(li = c->nodes; li != NULL; li = li->next) {
473                 Node *n = li->data;
474                 if(n->type == METHOD_NODE) {
475                         Method *m = (Method *)n;
476                         check_func_arg_check_method(m);
477                 }
478         }
479 }
480
481 void
482 check_func_attrs(Class *c)
483 {
484   GList *li;
485   for (li = c->nodes; li != NULL; li = li->next) {
486     Node *n = li->data;
487     if (n->type == METHOD_NODE) {
488       Method *m = (Method *)n;
489       if ((m->method == INIT_METHOD ||
490            m->method == CLASS_INIT_METHOD)
491           && (m->funcattrs != NULL && strlen(m->funcattrs) != 0)) {
492         /* This is actually dead code at the moment, since the parser
493            doesn't accept attributes to the init or class_init
494            syntactic forms anyway.  But it could easily be made to do
495            so, and also for virtual override and signal methods, and
496            then we could give kinder error messages here.  */
497         error_print (GOB_ERROR, m->line_no,
498                      "function attributes (G_GNUC_PRINTF, etc.) aren't "
499                      "supported for the init or class_init methods");
500       }
501     }
502   }
503 }
504
505 void
506 check_for_class_destructors (Class *c)
507 {
508         GList *li;
509         for (li = c->nodes; li != NULL; li = li->next) {
510                 Node *n = li->data;
511                 if (n->type == VARIABLE_NODE) {
512                         Variable *v = (Variable *)n;
513                         if (v->destructor != NULL &&
514                             v->scope == CLASS_SCOPE) {
515                                 error_print (GOB_WARN, v->line_no,
516                                              "classwide members cannot have "
517                                              "destructors since the classes "
518                                              "are static and never get "
519                                              "destroyed anyway");
520                         }
521                 }
522         }
523 }
524
525 int
526 count_signals(Class *c)
527 {
528         int num = 0;
529         GList *li;
530         for(li = c->nodes; li != NULL; li = li->next) {
531                 Node *n = li->data;
532                 if(n->type == METHOD_NODE) {
533                         Method *m = (Method *)n;
534                         if(m->method == SIGNAL_LAST_METHOD ||
535                            m->method == SIGNAL_FIRST_METHOD)
536                                 num++;
537                 }
538         }
539         return num;
540 }
541
542 int
543 count_set_properties (Class *c)
544 {
545         int num = 0;
546         GList *li;
547         for (li = c->nodes; li != NULL; li = li->next) {
548                 Node *n = li->data;
549                 Property *p = li->data;
550                 if (n->type == PROPERTY_NODE &&
551                     p->set != NULL)
552                         num ++;
553         }
554         return num;
555 }
556
557 int
558 count_get_properties (Class *c)
559 {
560         int num = 0;
561         GList *li;
562         for (li = c->nodes; li != NULL; li = li->next) {
563                 Node *n = li->data;
564                 Property *p = li->data;
565                 if (n->type == PROPERTY_NODE &&
566                     p->get != NULL)
567                         num ++;
568         }
569         return num;
570 }
571
572
573 int
574 count_set_arguments(Class *c)
575 {
576         int num = 0;
577         GList *li;
578         for(li = c->nodes; li != NULL; li = li->next) {
579                 Node *n = li->data;
580                 Argument *a = li->data;
581                 if(n->type == ARGUMENT_NODE &&
582                    a->set)
583                         num ++;
584         }
585         return num;
586 }
587
588 int
589 count_get_arguments(Class *c)
590 {
591         int num = 0;
592         GList *li;
593         for(li = c->nodes; li != NULL; li = li->next) {
594                 Node *n = li->data;
595                 Argument *a = li->data;
596                 if(n->type == ARGUMENT_NODE &&
597                    a->get)
598                         num ++;
599         }
600         return num;
601 }
602
603 int
604 count_overrides(Class *c)
605 {
606         int num = 0;
607         GList *li;
608         for(li = c->nodes; li != NULL; li = li->next) {
609                 Node *n = li->data;
610                 if(n->type == METHOD_NODE) {
611                         Method *m = (Method *)n;
612                         if(m->method == OVERRIDE_METHOD)
613                                 num++;
614                 }
615         }
616         return num;
617 }
618
619 int
620 count_privates(Class *c)
621 {
622         int num = 0;
623         GList *li;
624         for(li = c->nodes; li != NULL; li = li->next) {
625                 Node *n = li->data;
626                 if(n->type == VARIABLE_NODE) {
627                         Variable *v = (Variable *)n;
628                         if(v->scope == PRIVATE_SCOPE)
629                                 num++;
630                 }
631         }
632         return num;
633 }
634
635 int
636 count_protecteds (Class *c)
637 {
638         int num = 0;
639         GList *li;
640         for (li = c->nodes; li != NULL; li = li->next) {
641                 Node *n = li->data;
642                 if(n->type == METHOD_NODE) {
643                         Method *m = (Method *)n;
644                         if(m->scope == PROTECTED_SCOPE)
645                                 num++;
646                 }
647         }
648         return num;
649 }
650
651 int
652 count_unreftors (Class *c)
653 {
654         int num = 0;
655         GList *li;
656         for (li = c->nodes; li != NULL; li = li->next) {
657                 Node *n = li->data;
658                 if (n->type == VARIABLE_NODE) {
659                         Variable *v = (Variable *)n;
660                         if (v->destructor != NULL &&
661                             v->destructor_unref &&
662                             v->scope != CLASS_SCOPE)
663                                 num++;
664                 }
665         }
666         return num;
667 }
668
669 int
670 count_destructors (Class *c)
671 {
672         int num = 0;
673         GList *li;
674         for (li = c->nodes; li != NULL; li = li->next) {
675                 Node *n = li->data;
676                 if (n->type == VARIABLE_NODE) {
677                         Variable *v = (Variable *)n;
678                         if (v->destructor != NULL &&
679                             ! v->destructor_unref &&
680                             v->scope != CLASS_SCOPE)
681                                 num++;
682                 }
683         }
684         return num;
685 }
686
687 int
688 count_initializers (Class *c)
689 {
690         int num = 0;
691         GList *li;
692         for (li = c->nodes; li != NULL; li = li->next) {
693                 Node *n = li->data;
694                 if (n->type == VARIABLE_NODE) {
695                         Variable *v = (Variable *)n;
696                         if (v->initializer != NULL)
697                                 num++;
698                 }
699         }
700         return num;
701 }
702
703 int
704 count_glade_widgets (Class *c)
705 {
706         int num = 0;
707         GList *li;
708         for (li = c->nodes; li != NULL; li = li->next) {
709                 Node *n = li->data;
710                 if (n->type == VARIABLE_NODE) {
711                         Variable *v = (Variable *)n;
712                         if (v->glade_widget)
713                                 num++;
714                 }
715         }
716         return num;
717 }
718
719 gboolean
720 find_get_type (Class *c)
721 {
722         GList *li;
723         for (li = c->nodes; li != NULL; li = li->next) {
724                 Node *n = li->data;
725                 Method *m = (Method *)n;
726                 if (n->type == METHOD_NODE &&
727                     strcmp (m->id, "get_type") == 0) {
728                         if (m->method != REGULAR_METHOD ||
729                             m->scope != PUBLIC_SCOPE ||
730                             m->args != NULL) {
731                                 error_printf (GOB_ERROR, m->line_no,
732                                               "get_type method must be a "
733                                               "regular public method with "
734                                               "no arguments");
735                         }
736                         return TRUE;
737                 }
738         }
739
740         return FALSE;
741 }