]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
Replace gnulib patch with new common helper macro.
[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
199                 if (n == node || line_no >= nline_no
200                     || gob_strcasecmp (nid, id) != 0)
201                 {
202                         continue;
203                 }
204                 error_printf (GOB_ERROR, nline_no,
205                               "named symbol (argument or signal) '%s' "
206                               "redefined, first defined on line %d "
207                               "(case insensitive)",
208                               id, line_no);
209         }
210 }
211
212 void
213 check_duplicate_signals_args (Class *c)
214 {
215         GList *li;
216         for (li = c->nodes; li != NULL; li = li->next) {
217                 Node *n = li->data;
218                 if (n->type == METHOD_NODE) {
219                         Method *m = (Method *)n;
220                         if(m->method == SIGNAL_LAST_METHOD ||
221                            m->method == SIGNAL_FIRST_METHOD)
222                                 check_duplicate_named (c, n, m->id,
223                                                        m->line_no);
224                 } else if (n->type == PROPERTY_NODE) {
225                         Property *p = (Property *)n;
226                         check_duplicate_named (c, n, p->name, p->line_no);
227                 } else if (n->type == ARGUMENT_NODE) {
228                         Argument *a = (Argument *)n;
229                         check_duplicate_named (c, n, a->name, a->line_no);
230                 }
231         }
232 }
233
234 void
235 check_public_new(Class *c)
236 {
237         GList *li;
238         for(li = c->nodes; li != NULL; li = li->next) {
239                 Node *n = li->data;
240                 if(n->type == METHOD_NODE) {
241                         Method *m = (Method *)n;
242                         if((strcmp(m->id, "new")==0) &&
243                            (m->method != REGULAR_METHOD ||
244                             m->scope != PUBLIC_SCOPE))
245                                 error_print(GOB_WARN, m->line_no,
246                                             "'new' should be a regular\n"
247                                             "public method");
248                 }
249         }
250 }
251
252 void
253 check_vararg(Class *c)
254 {
255         GList *li;
256         for(li = c->nodes; li != NULL; li = li->next) {
257                 Node *n = li->data;
258                 if(n->type == METHOD_NODE) {
259                         Method *m = (Method *)n;
260                         if( ! m->vararg)
261                                 continue;
262                         if(m->method == OVERRIDE_METHOD ||
263                            m->method == SIGNAL_LAST_METHOD ||
264                            m->method == SIGNAL_FIRST_METHOD ||
265                            m->method == VIRTUAL_METHOD) {
266                                 error_print(GOB_ERROR, m->line_no,
267                                             "signals, overrides and virtuals, "
268                                             "can't have variable argument "
269                                             "lists");
270                         }
271                 }
272         }
273 }
274
275 void
276 check_firstarg(Class *c)
277 {
278         GList *li;
279         for(li = c->nodes; li != NULL; li = li->next) {
280                 Node *n = li->data;
281                 if(n->type == METHOD_NODE) {
282                         Method *m = (Method *)n;
283                         if(m->args)
284                                 continue;
285                         if(m->method == OVERRIDE_METHOD ||
286                            m->method == SIGNAL_LAST_METHOD ||
287                            m->method == SIGNAL_FIRST_METHOD ||
288                            m->method == VIRTUAL_METHOD) {
289                                 error_print(GOB_ERROR, m->line_no,
290                                             "signals, overrides and virtuals, "
291                                             "can't have no arguments");
292                         }
293                 }
294         }
295 }
296
297 void
298 check_nonvoidempty(Class *c)
299 {
300         GList *li;
301         for(li = c->nodes; li != NULL; li = li->next) {
302                 Node *n = li->data;
303                 if(n->type == METHOD_NODE) {
304                         Method *m = (Method *)n;
305                         if(m->method != REGULAR_METHOD)
306                                 continue;
307                         if(!(strcmp(m->mtype->name, "void")==0 &&
308                              m->mtype->pointer == NULL) &&
309                            !m->cbuf) {
310                                 error_print(GOB_WARN, m->line_no,
311                                             "non-void empty method found, "
312                                             "regular non-void function should "
313                                             "not be empty.");
314                                 /* add a body here, so that the user will also
315                                    get a warning from gcc, and so that it will
316                                    at least point him to the prototype of the
317                                    function in the .gob file */
318                                 m->cbuf = g_strdup("/*empty*/");
319                                 m->ccode_line = m->line_no;
320                         }
321                 }
322         }
323 }
324
325 void
326 check_signal_args (Class *c)
327 {
328         GList *li;
329         for (li = c->nodes; li != NULL; li = li->next) {
330                 Node *n = li->data;
331                 if(n->type == METHOD_NODE) {
332                         Method *m = (Method *)n;
333                         GList *l;
334                         if(m->method != SIGNAL_LAST_METHOD &&
335                            m->method != SIGNAL_FIRST_METHOD)
336                                 continue;
337
338                         for (l = m->gtktypes; l != NULL; l = l->next) {
339                                 if (strcmp (l->data, "BOXED") == 0) {
340                                         error_printf (GOB_ERROR, m->line_no,
341                                                       "BOXED not allowed as "
342                                                       "a signal argument, use "
343                                                       "POINTER, or BOXED_*");
344                                         continue;
345                                 } else if (strcmp (l->data, "FLAGS") == 0) {
346                                         error_printf (GOB_ERROR, m->line_no,
347                                                       "FLAGS not allowed as "
348                                                       "a signal argument, use "
349                                                       "UINT");
350                                         continue;
351                                 }
352                                 if (get_cast (l->data, FALSE))
353                                         continue;
354                                 error_printf (GOB_ERROR, m->line_no,
355                                               "Unknown GTK+ type '%s' "
356                                               "among signal types",
357                                               (char *)l->data);
358                         }
359                 }
360         }
361 }
362
363 void
364 check_argument_types (Class *c)
365 {
366         GList *li;
367         for (li = c->nodes; li != NULL; li = li->next) {
368                 Node *n = li->data;
369                 if(n->type == ARGUMENT_NODE) {
370                         Argument *a = (Argument *)n;
371                         if(get_cast(a->gtktype, FALSE))
372                                 continue;
373                         error_printf(GOB_ERROR, a->line_no,
374                                      "Unknown GLib type '%s' "
375                                      "as argument type",
376                                      a->gtktype);
377                 }
378         }
379 }
380
381 void
382 check_property_types (Class *c)
383 {
384         GList *li;
385         for (li = c->nodes; li != NULL; li = li->next) {
386                 Node *n = li->data;
387                 if (n->type == PROPERTY_NODE) {
388                         Property *p = (Property *)n;
389                         if (get_cast (p->gtktype, FALSE))
390                                 continue;
391                         error_printf (GOB_ERROR, p->line_no,
392                                       "Unknown GLib type '%s' "
393                                       "as property type",
394                                       p->gtktype);
395                 }
396         }
397 }
398
399 static void
400 check_func_arg_check_func_arg(Method *m, FuncArg *fa)
401 {
402         GList *li;
403         char *s;
404
405         if( ! fa->checks)
406                 return;
407
408         if(strcmp(fa->atype->name, "void") == 0 &&
409            fa->atype->pointer == NULL) {
410                 error_print(GOB_ERROR, m->line_no,
411                             "Running checks on a void function argument");
412                 return;
413         }
414         
415         for(li = fa->checks; li; li = li->next) {
416                 Check *ch = li->data;
417                 if(ch->chtype == TYPE_CHECK) {
418                         char *p;
419                         gboolean got_type = FALSE;
420                         s = g_strdup(fa->atype->name);
421                         p = strtok(s, " ");
422                         if( ! p) {
423                                 g_free(s);
424                                 goto type_check_error;
425                         }
426                         while(p) {
427                                 if(strcmp(p, "const") != 0) {
428                                         if(got_type) {
429                                                 g_free(s);
430                                                 goto type_check_error;
431                                         }
432                                         got_type = TRUE;
433                                 }
434                                 p = strtok(NULL, " ");
435                         }
436                         g_free(s);
437                         if( ! got_type)
438                                 goto type_check_error;
439
440                         if(fa->atype->pointer == NULL ||
441                            (strcmp(fa->atype->pointer, "*") != 0 &&
442                             strcmp(fa->atype->pointer, "* const") != 0 &&
443                             strcmp(fa->atype->pointer, "const *") != 0))
444                                 goto type_check_error;
445                 }
446         }
447         return;
448
449 type_check_error:
450         if(fa->atype->pointer)
451                 error_printf(GOB_ERROR, m->line_no,
452                              "Cannot check the type of '%s %s'",
453                              fa->atype->name, fa->atype->pointer);
454         else
455                 error_printf(GOB_ERROR, m->line_no,
456                              "Cannot check the type of '%s'",
457                              fa->atype->name);
458 }
459
460 static void
461 check_func_arg_check_method(Method *m)
462 {
463         GList *li;
464         for(li = m->args; li; li = li->next) {
465                 FuncArg *fa = li->data;
466                 check_func_arg_check_func_arg(m, fa);
467         }
468 }
469
470 void
471 check_func_arg_checks(Class *c)
472 {
473         GList *li;
474         for(li = c->nodes; li != NULL; li = li->next) {
475                 Node *n = li->data;
476                 if(n->type == METHOD_NODE) {
477                         Method *m = (Method *)n;
478                         check_func_arg_check_method(m);
479                 }
480         }
481 }
482
483 void
484 check_func_attrs(Class *c)
485 {
486   GList *li;
487   for (li = c->nodes; li != NULL; li = li->next) {
488     Node *n = li->data;
489     if (n->type == METHOD_NODE) {
490       Method *m = (Method *)n;
491       if ((m->method == INIT_METHOD ||
492            m->method == CLASS_INIT_METHOD)
493           && (m->funcattrs != NULL && strlen(m->funcattrs) != 0)) {
494         /* This is actually dead code at the moment, since the parser
495            doesn't accept attributes to the init or class_init
496            syntactic forms anyway.  But it could easily be made to do
497            so, and also for virtual override and signal methods, and
498            then we could give kinder error messages here.  */
499         error_print (GOB_ERROR, m->line_no,
500                      "function attributes (G_GNUC_PRINTF, etc.) aren't "
501                      "supported for the init or class_init methods");
502       }
503     }
504   }
505 }
506
507 void
508 check_for_class_destructors (Class *c)
509 {
510         GList *li;
511         for (li = c->nodes; li != NULL; li = li->next) {
512                 Node *n = li->data;
513                 if (n->type == VARIABLE_NODE) {
514                         Variable *v = (Variable *)n;
515                         if (v->destructor != NULL &&
516                             v->scope == CLASS_SCOPE) {
517                                 error_print (GOB_WARN, v->line_no,
518                                              "classwide members cannot have "
519                                              "destructors since the classes "
520                                              "are static and never get "
521                                              "destroyed anyway");
522                         }
523                 }
524         }
525 }
526
527 int
528 count_signals(Class *c)
529 {
530         int num = 0;
531         GList *li;
532         for(li = c->nodes; li != NULL; li = li->next) {
533                 Node *n = li->data;
534                 if(n->type == METHOD_NODE) {
535                         Method *m = (Method *)n;
536                         if(m->method == SIGNAL_LAST_METHOD ||
537                            m->method == SIGNAL_FIRST_METHOD)
538                                 num++;
539                 }
540         }
541         return num;
542 }
543
544 int
545 count_set_properties (Class *c)
546 {
547         int num = 0;
548         GList *li;
549         for (li = c->nodes; li != NULL; li = li->next) {
550                 Node *n = li->data;
551                 Property *p = li->data;
552                 if (n->type == PROPERTY_NODE &&
553                     p->set != NULL)
554                         num ++;
555         }
556         return num;
557 }
558
559 int
560 count_get_properties (Class *c)
561 {
562         int num = 0;
563         GList *li;
564         for (li = c->nodes; li != NULL; li = li->next) {
565                 Node *n = li->data;
566                 Property *p = li->data;
567                 if (n->type == PROPERTY_NODE &&
568                     p->get != NULL)
569                         num ++;
570         }
571         return num;
572 }
573
574
575 int
576 count_set_arguments(Class *c)
577 {
578         int num = 0;
579         GList *li;
580         for(li = c->nodes; li != NULL; li = li->next) {
581                 Node *n = li->data;
582                 Argument *a = li->data;
583                 if(n->type == ARGUMENT_NODE &&
584                    a->set)
585                         num ++;
586         }
587         return num;
588 }
589
590 int
591 count_get_arguments(Class *c)
592 {
593         int num = 0;
594         GList *li;
595         for(li = c->nodes; li != NULL; li = li->next) {
596                 Node *n = li->data;
597                 Argument *a = li->data;
598                 if(n->type == ARGUMENT_NODE &&
599                    a->get)
600                         num ++;
601         }
602         return num;
603 }
604
605 int
606 count_overrides(Class *c)
607 {
608         int num = 0;
609         GList *li;
610         for(li = c->nodes; li != NULL; li = li->next) {
611                 Node *n = li->data;
612                 if(n->type == METHOD_NODE) {
613                         Method *m = (Method *)n;
614                         if(m->method == OVERRIDE_METHOD)
615                                 num++;
616                 }
617         }
618         return num;
619 }
620
621 int
622 count_privates(Class *c)
623 {
624         int num = 0;
625         GList *li;
626         for(li = c->nodes; li != NULL; li = li->next) {
627                 Node *n = li->data;
628                 if(n->type == VARIABLE_NODE) {
629                         Variable *v = (Variable *)n;
630                         if(v->scope == PRIVATE_SCOPE)
631                                 num++;
632                 }
633         }
634         return num;
635 }
636
637 int
638 count_protecteds (Class *c)
639 {
640         int num = 0;
641         GList *li;
642         for (li = c->nodes; li != NULL; li = li->next) {
643                 Node *n = li->data;
644                 if(n->type == METHOD_NODE) {
645                         Method *m = (Method *)n;
646                         if(m->scope == PROTECTED_SCOPE)
647                                 num++;
648                 }
649         }
650         return num;
651 }
652
653 int
654 count_unreftors (Class *c)
655 {
656         int num = 0;
657         GList *li;
658         for (li = c->nodes; li != NULL; li = li->next) {
659                 Node *n = li->data;
660                 if (n->type == VARIABLE_NODE) {
661                         Variable *v = (Variable *)n;
662                         if (v->destructor != NULL &&
663                             v->destructor_unref &&
664                             v->scope != CLASS_SCOPE)
665                                 num++;
666                 }
667         }
668         return num;
669 }
670
671 int
672 count_destructors (Class *c)
673 {
674         int num = 0;
675         GList *li;
676         for (li = c->nodes; li != NULL; li = li->next) {
677                 Node *n = li->data;
678                 if (n->type == VARIABLE_NODE) {
679                         Variable *v = (Variable *)n;
680                         if (v->destructor != NULL &&
681                             ! v->destructor_unref &&
682                             v->scope != CLASS_SCOPE)
683                                 num++;
684                 }
685         }
686         return num;
687 }
688
689 int
690 count_initializers (Class *c)
691 {
692         int num = 0;
693         GList *li;
694         for (li = c->nodes; li != NULL; li = li->next) {
695                 Node *n = li->data;
696                 if (n->type == VARIABLE_NODE) {
697                         Variable *v = (Variable *)n;
698                         if (v->initializer != NULL)
699                                 num++;
700                 }
701         }
702         return num;
703 }
704
705 int
706 count_glade_widgets (Class *c)
707 {
708         int num = 0;
709         GList *li;
710         for (li = c->nodes; li != NULL; li = li->next) {
711                 Node *n = li->data;
712                 if (n->type == VARIABLE_NODE) {
713                         Variable *v = (Variable *)n;
714                         if (v->glade_widget)
715                                 num++;
716                 }
717         }
718         return num;
719 }
720
721 gboolean
722 find_get_type (Class *c)
723 {
724         GList *li;
725         for (li = c->nodes; li != NULL; li = li->next) {
726                 Node *n = li->data;
727                 Method *m = (Method *)n;
728                 if (n->type == METHOD_NODE &&
729                     strcmp (m->id, "get_type") == 0) {
730                         if (m->method != REGULAR_METHOD ||
731                             m->scope != PUBLIC_SCOPE ||
732                             m->args != NULL) {
733                                 error_printf (GOB_ERROR, m->line_no,
734                                               "get_type method must be a "
735                                               "regular public method with "
736                                               "no arguments");
737                         }
738                         return TRUE;
739                 }
740         }
741
742         return FALSE;
743 }