]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
b30d0f8122c8cf9a292b0078f9b76ba957f0ab2b
[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 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 (get_cast (l->data, FALSE))
338                                         continue;
339                                 error_printf (GOB_ERROR, m->line_no,
340                                               "Unknown GTK+ type '%s' "
341                                               "among signal types",
342                                               (char *)l->data);
343                         }
344                 }
345         }
346 }
347
348 void
349 check_argument_types (Class *c)
350 {
351         GList *li;
352         for (li = c->nodes; li != NULL; li = li->next) {
353                 Node *n = li->data;
354                 if(n->type == ARGUMENT_NODE) {
355                         Argument *a = (Argument *)n;
356                         if(get_cast(a->gtktype, FALSE))
357                                 continue;
358                         error_printf(GOB_ERROR, a->line_no,
359                                      "Unknown GLib type '%s' "
360                                      "as argument type",
361                                      a->gtktype);
362                 }
363         }
364 }
365
366 void
367 check_property_types (Class *c)
368 {
369         GList *li;
370         for (li = c->nodes; li != NULL; li = li->next) {
371                 Node *n = li->data;
372                 if (n->type == PROPERTY_NODE) {
373                         Property *p = (Property *)n;
374                         if (get_cast (p->gtktype, FALSE))
375                                 continue;
376                         error_printf (GOB_ERROR, p->line_no,
377                                       "Unknown GLib type '%s' "
378                                       "as property type",
379                                       p->gtktype);
380                 }
381         }
382 }
383
384 static void
385 check_func_arg_check_func_arg(Method *m, FuncArg *fa)
386 {
387         GList *li;
388         char *s;
389
390         if( ! fa->checks)
391                 return;
392
393         if(strcmp(fa->atype->name, "void") == 0 &&
394            fa->atype->pointer == NULL) {
395                 error_print(GOB_ERROR, m->line_no,
396                             "Running checks on a void function argument");
397                 return;
398         }
399         
400         for(li = fa->checks; li; li = li->next) {
401                 Check *ch = li->data;
402                 if(ch->chtype == TYPE_CHECK) {
403                         char *p;
404                         gboolean got_type = FALSE;
405                         s = g_strdup(fa->atype->name);
406                         p = strtok(s, " ");
407                         if( ! p) {
408                                 g_free(s);
409                                 goto type_check_error;
410                         }
411                         while(p) {
412                                 if(strcmp(p, "const") != 0) {
413                                         if(got_type) {
414                                                 g_free(s);
415                                                 goto type_check_error;
416                                         }
417                                         got_type = TRUE;
418                                 }
419                                 p = strtok(NULL, " ");
420                         }
421                         g_free(s);
422                         if( ! got_type)
423                                 goto type_check_error;
424
425                         if(fa->atype->pointer == NULL ||
426                            (strcmp(fa->atype->pointer, "*") != 0 &&
427                             strcmp(fa->atype->pointer, "* const") != 0 &&
428                             strcmp(fa->atype->pointer, "const *") != 0))
429                                 goto type_check_error;
430                 }
431         }
432         return;
433
434 type_check_error:
435         if(fa->atype->pointer)
436                 error_printf(GOB_ERROR, m->line_no,
437                              "Cannot check the type of '%s %s'",
438                              fa->atype->name, fa->atype->pointer);
439         else
440                 error_printf(GOB_ERROR, m->line_no,
441                              "Cannot check the type of '%s'",
442                              fa->atype->name);
443 }
444
445 static void
446 check_func_arg_check_method(Method *m)
447 {
448         GList *li;
449         for(li = m->args; li; li = li->next) {
450                 FuncArg *fa = li->data;
451                 check_func_arg_check_func_arg(m, fa);
452         }
453 }
454
455 void
456 check_func_arg_checks(Class *c)
457 {
458         GList *li;
459         for(li = c->nodes; li != NULL; li = li->next) {
460                 Node *n = li->data;
461                 if(n->type == METHOD_NODE) {
462                         Method *m = (Method *)n;
463                         check_func_arg_check_method(m);
464                 }
465         }
466 }
467
468 int
469 count_signals(Class *c)
470 {
471         int num = 0;
472         GList *li;
473         for(li = c->nodes; li != NULL; li = li->next) {
474                 Node *n = li->data;
475                 if(n->type == METHOD_NODE) {
476                         Method *m = (Method *)n;
477                         if(m->method == SIGNAL_LAST_METHOD ||
478                            m->method == SIGNAL_FIRST_METHOD)
479                                 num++;
480                 }
481         }
482         return num;
483 }
484
485 int
486 count_set_properties (Class *c)
487 {
488         int num = 0;
489         GList *li;
490         for (li = c->nodes; li != NULL; li = li->next) {
491                 Node *n = li->data;
492                 Property *p = li->data;
493                 if (n->type == PROPERTY_NODE &&
494                     p->set != NULL)
495                         num ++;
496         }
497         return num;
498 }
499
500 int
501 count_get_properties (Class *c)
502 {
503         int num = 0;
504         GList *li;
505         for (li = c->nodes; li != NULL; li = li->next) {
506                 Node *n = li->data;
507                 Property *p = li->data;
508                 if (n->type == PROPERTY_NODE &&
509                     p->get != NULL)
510                         num ++;
511         }
512         return num;
513 }
514
515
516 int
517 count_set_arguments(Class *c)
518 {
519         int num = 0;
520         GList *li;
521         for(li = c->nodes; li != NULL; li = li->next) {
522                 Node *n = li->data;
523                 Argument *a = li->data;
524                 if(n->type == ARGUMENT_NODE &&
525                    a->set)
526                         num ++;
527         }
528         return num;
529 }
530
531 int
532 count_get_arguments(Class *c)
533 {
534         int num = 0;
535         GList *li;
536         for(li = c->nodes; li != NULL; li = li->next) {
537                 Node *n = li->data;
538                 Argument *a = li->data;
539                 if(n->type == ARGUMENT_NODE &&
540                    a->get)
541                         num ++;
542         }
543         return num;
544 }
545
546 int
547 count_overrides(Class *c)
548 {
549         int num = 0;
550         GList *li;
551         for(li = c->nodes; li != NULL; li = li->next) {
552                 Node *n = li->data;
553                 if(n->type == METHOD_NODE) {
554                         Method *m = (Method *)n;
555                         if(m->method == OVERRIDE_METHOD)
556                                 num++;
557                 }
558         }
559         return num;
560 }
561
562 int
563 count_privates(Class *c)
564 {
565         int num = 0;
566         GList *li;
567         for(li = c->nodes; li != NULL; li = li->next) {
568                 Node *n = li->data;
569                 if(n->type == VARIABLE_NODE) {
570                         Variable *v = (Variable *)n;
571                         if(v->scope == PRIVATE_SCOPE)
572                                 num++;
573                 }
574         }
575         return num;
576 }
577
578 int
579 count_protecteds (Class *c)
580 {
581         int num = 0;
582         GList *li;
583         for (li = c->nodes; li != NULL; li = li->next) {
584                 Node *n = li->data;
585                 if(n->type == METHOD_NODE) {
586                         Method *m = (Method *)n;
587                         if(m->scope == PROTECTED_SCOPE)
588                                 num++;
589                 }
590         }
591         return num;
592 }
593
594 int
595 count_unreftors (Class *c)
596 {
597         int num = 0;
598         GList *li;
599         for (li = c->nodes; li != NULL; li = li->next) {
600                 Node *n = li->data;
601                 if (n->type == VARIABLE_NODE) {
602                         Variable *v = (Variable *)n;
603                         if (v->destructor != NULL &&
604                             v->destructor_unref)
605                                 num++;
606                 }
607         }
608         return num;
609 }
610
611 int
612 count_destructors (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 == VARIABLE_NODE) {
619                         Variable *v = (Variable *)n;
620                         if (v->destructor != NULL &&
621                             ! v->destructor_unref)
622                                 num++;
623                 }
624         }
625         return num;
626 }
627
628 int
629 count_initializers (Class *c)
630 {
631         int num = 0;
632         GList *li;
633         for (li = c->nodes; li != NULL; li = li->next) {
634                 Node *n = li->data;
635                 if (n->type == VARIABLE_NODE) {
636                         Variable *v = (Variable *)n;
637                         if (v->initializer != NULL)
638                                 num++;
639                 }
640         }
641         return num;
642 }
643
644 gboolean
645 find_get_type (Class *c)
646 {
647         GList *li;
648         for (li = c->nodes; li != NULL; li = li->next) {
649                 Node *n = li->data;
650                 Method *m = (Method *)n;
651                 if (n->type == METHOD_NODE &&
652                     strcmp (m->id, "get_type") == 0) {
653                         if (m->method != REGULAR_METHOD ||
654                             m->scope != PUBLIC_SCOPE ||
655                             m->args != NULL) {
656                                 error_printf (GOB_ERROR, m->line_no,
657                                               "get_type method must be a "
658                                               "regular public method with "
659                                               "no arguments");
660                         }
661                         return TRUE;
662                 }
663         }
664
665         return FALSE;
666 }