]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
63f44cc6f28babdcb66640b17eb8c344c8a92470
[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");
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_for_class_destructors (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 == VARIABLE_NODE) {
488                         Variable *v = (Variable *)n;
489                         if (v->destructor != NULL &&
490                             v->scope == CLASS_SCOPE) {
491                                 error_print (GOB_WARN, v->line_no,
492                                              "classwide members cannot have "
493                                              "destructors since the classes "
494                                              "are static and never get "
495                                              "destroyed anyway");
496                         }
497                 }
498         }
499 }
500
501 int
502 count_signals(Class *c)
503 {
504         int num = 0;
505         GList *li;
506         for(li = c->nodes; li != NULL; li = li->next) {
507                 Node *n = li->data;
508                 if(n->type == METHOD_NODE) {
509                         Method *m = (Method *)n;
510                         if(m->method == SIGNAL_LAST_METHOD ||
511                            m->method == SIGNAL_FIRST_METHOD)
512                                 num++;
513                 }
514         }
515         return num;
516 }
517
518 int
519 count_set_properties (Class *c)
520 {
521         int num = 0;
522         GList *li;
523         for (li = c->nodes; li != NULL; li = li->next) {
524                 Node *n = li->data;
525                 Property *p = li->data;
526                 if (n->type == PROPERTY_NODE &&
527                     p->set != NULL)
528                         num ++;
529         }
530         return num;
531 }
532
533 int
534 count_get_properties (Class *c)
535 {
536         int num = 0;
537         GList *li;
538         for (li = c->nodes; li != NULL; li = li->next) {
539                 Node *n = li->data;
540                 Property *p = li->data;
541                 if (n->type == PROPERTY_NODE &&
542                     p->get != NULL)
543                         num ++;
544         }
545         return num;
546 }
547
548
549 int
550 count_set_arguments(Class *c)
551 {
552         int num = 0;
553         GList *li;
554         for(li = c->nodes; li != NULL; li = li->next) {
555                 Node *n = li->data;
556                 Argument *a = li->data;
557                 if(n->type == ARGUMENT_NODE &&
558                    a->set)
559                         num ++;
560         }
561         return num;
562 }
563
564 int
565 count_get_arguments(Class *c)
566 {
567         int num = 0;
568         GList *li;
569         for(li = c->nodes; li != NULL; li = li->next) {
570                 Node *n = li->data;
571                 Argument *a = li->data;
572                 if(n->type == ARGUMENT_NODE &&
573                    a->get)
574                         num ++;
575         }
576         return num;
577 }
578
579 int
580 count_overrides(Class *c)
581 {
582         int num = 0;
583         GList *li;
584         for(li = c->nodes; li != NULL; li = li->next) {
585                 Node *n = li->data;
586                 if(n->type == METHOD_NODE) {
587                         Method *m = (Method *)n;
588                         if(m->method == OVERRIDE_METHOD)
589                                 num++;
590                 }
591         }
592         return num;
593 }
594
595 int
596 count_privates(Class *c)
597 {
598         int num = 0;
599         GList *li;
600         for(li = c->nodes; li != NULL; li = li->next) {
601                 Node *n = li->data;
602                 if(n->type == VARIABLE_NODE) {
603                         Variable *v = (Variable *)n;
604                         if(v->scope == PRIVATE_SCOPE)
605                                 num++;
606                 }
607         }
608         return num;
609 }
610
611 int
612 count_protecteds (Class *c)
613 {
614         int num = 0;
615         GList *li;
616         for (li = c->nodes; li != NULL; li = li->next) {
617                 Node *n = li->data;
618                 if(n->type == METHOD_NODE) {
619                         Method *m = (Method *)n;
620                         if(m->scope == PROTECTED_SCOPE)
621                                 num++;
622                 }
623         }
624         return num;
625 }
626
627 int
628 count_unreftors (Class *c)
629 {
630         int num = 0;
631         GList *li;
632         for (li = c->nodes; li != NULL; li = li->next) {
633                 Node *n = li->data;
634                 if (n->type == VARIABLE_NODE) {
635                         Variable *v = (Variable *)n;
636                         if (v->destructor != NULL &&
637                             v->destructor_unref &&
638                             v->scope != CLASS_SCOPE)
639                                 num++;
640                 }
641         }
642         return num;
643 }
644
645 int
646 count_destructors (Class *c)
647 {
648         int num = 0;
649         GList *li;
650         for (li = c->nodes; li != NULL; li = li->next) {
651                 Node *n = li->data;
652                 if (n->type == VARIABLE_NODE) {
653                         Variable *v = (Variable *)n;
654                         if (v->destructor != NULL &&
655                             ! v->destructor_unref &&
656                             v->scope != CLASS_SCOPE)
657                                 num++;
658                 }
659         }
660         return num;
661 }
662
663 int
664 count_initializers (Class *c)
665 {
666         int num = 0;
667         GList *li;
668         for (li = c->nodes; li != NULL; li = li->next) {
669                 Node *n = li->data;
670                 if (n->type == VARIABLE_NODE) {
671                         Variable *v = (Variable *)n;
672                         if (v->initializer != NULL)
673                                 num++;
674                 }
675         }
676         return num;
677 }
678
679 int
680 count_glade_widgets (Class *c)
681 {
682         int num = 0;
683         GList *li;
684         for (li = c->nodes; li != NULL; li = li->next) {
685                 Node *n = li->data;
686                 if (n->type == VARIABLE_NODE) {
687                         Variable *v = (Variable *)n;
688                         if (v->glade_widget)
689                                 num++;
690                 }
691         }
692         return num;
693 }
694
695 gboolean
696 find_get_type (Class *c)
697 {
698         GList *li;
699         for (li = c->nodes; li != NULL; li = li->next) {
700                 Node *n = li->data;
701                 Method *m = (Method *)n;
702                 if (n->type == METHOD_NODE &&
703                     strcmp (m->id, "get_type") == 0) {
704                         if (m->method != REGULAR_METHOD ||
705                             m->scope != PUBLIC_SCOPE ||
706                             m->args != NULL) {
707                                 error_printf (GOB_ERROR, m->line_no,
708                                               "get_type method must be a "
709                                               "regular public method with "
710                                               "no arguments");
711                         }
712                         return TRUE;
713                 }
714         }
715
716         return FALSE;
717 }