]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
Release 1.0.2
[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  *
5  * Author: George Lebl
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the  Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  * USA.
21  */
22
23 #include "config.h"
24 #include <string.h>
25 #include <stdio.h>
26 #include <glib.h>
27
28 #include "treefuncs.h"
29 #include "main.h"
30 #include "util.h"
31
32 #include "checks.h"
33
34 static void
35 check_duplicate(Class *c, Node *node, char *id, int line_no,
36                 gboolean underscore)
37 {
38         GList *l;
39         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
40                 Node *n = l->data;
41                 char *nid;
42                 int nline_no;
43                 gboolean here_underscore = FALSE;
44                 char *s;
45                 if(n->type == METHOD_NODE) {
46                         Method *m = (Method *)n;
47
48                         /* override methods are checked separately */
49                         if(m->method == OVERRIDE_METHOD)
50                                 continue;
51
52                         nid = get_real_id(m->id);
53                         nline_no = m->line_no;
54
55                         if(m->id[0] == '_' && m->id[1] != '\0')
56                                 here_underscore = TRUE;
57                 } else if(n->type == VARIABLE_NODE) {
58                         Variable *v = (Variable *)n;
59                         nid = v->id;
60                         nline_no = v->line_no;
61                 } else
62                         continue;
63                 if(n == node ||
64                    line_no > nline_no ||
65                    n->type != node->type ||
66                    strcmp(nid, id) != 0)
67                         continue;
68                 /* this can only happen if the things were methods and
69                  * one had an underscore and the other one didn't */
70                 if(!no_kill_underscores && underscore != here_underscore)
71                         s = g_strdup_printf("symbol '%s' ('_%s') redefined, "
72                                             "first defined on line %d. "
73                                             "Note that '%s' and '_%s' are "
74                                             "eqivalent.",
75                                             id, id, line_no, id, id);
76                 else
77                         s = g_strdup_printf("symbol '%s' redefined, "
78                                             "first defined on line %d",
79                                             id, line_no);
80                 print_error(FALSE, s, nline_no);
81                 g_free(s);
82         }
83 }
84
85 void
86 check_duplicate_symbols(Class *c)
87 {
88         GList *l;
89         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
90                 Node *n = l->data;
91                 if(n->type == METHOD_NODE) {
92                         Method *m = (Method *)n;
93                         gboolean underscore = FALSE;
94                         /* override methods are checked separately */
95                         if(m->method == OVERRIDE_METHOD)
96                                 continue;
97                         if(m->id[0] == '_' && m->id[1] != '\0')
98                                 underscore = TRUE;
99                         check_duplicate(c, n, get_real_id(m->id), m->line_no,
100                                         underscore);
101                 } else if(n->type == VARIABLE_NODE) {
102                         Variable *v = (Variable *)n;
103                         check_duplicate(c, n, v->id, v->line_no, FALSE);
104                 }
105         }
106 }
107
108 static void
109 check_duplicate_override(Class *c, Method *method)
110 {
111         GList *l;
112         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
113                 Node *n = l->data;
114                 Method *m = (Method *)n;
115                 char *s;
116                 if(n->type != METHOD_NODE ||
117                    m->method != OVERRIDE_METHOD)
118                         continue;
119
120                 if(method == m ||
121                    method->line_no > m->line_no ||
122                    strcmp(m->id, method->id) != 0 ||
123                    strcmp(m->otype, method->otype) != 0)
124                         continue;
125                 s = g_strdup_printf("override '%s(%s)' redefined, "
126                                     "first defined on line %d",
127                                     m->id, m->otype, method->line_no);
128                 print_error(FALSE, s, m->line_no);
129                 g_free(s);
130         }
131 }
132
133 void
134 check_duplicate_overrides(Class *c)
135 {
136         GList *l;
137         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
138                 Node *n = l->data;
139                 Method *m = (Method *)n;
140                 if(n->type != METHOD_NODE ||
141                    m->method != OVERRIDE_METHOD)
142                         continue;
143                 check_duplicate_override(c, m);
144         }
145 }
146
147 void
148 check_bad_symbols(Class *c)
149 {
150         GList *l;
151         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
152                 Node *n = l->data;
153                 if(n->type == METHOD_NODE) {
154                         Method *m = (Method *)n;
155                         if((m->method == SIGNAL_LAST_METHOD ||
156                             m->method == SIGNAL_FIRST_METHOD ||
157                             m->method == VIRTUAL_METHOD) &&
158                            strcmp(m->id, "__parent__")==0) {
159                                 char *s;
160                                 s = g_strdup_printf("'%s' not allowed as an "
161                                                     "identifier of signal "
162                                                     "or virtual methods",
163                                                     m->id);
164                                 print_error(FALSE,s,m->line_no);
165                                 g_free(s);
166                         }
167                         if(m->method != INIT_METHOD &&
168                            m->method != CLASS_INIT_METHOD &&
169                            (strcmp(m->id, "init")==0 ||
170                             strcmp(m->id, "class_init")==0)) {
171                                 print_error(FALSE,"init, or class_init not "
172                                             "allowed as an "
173                                             "identifier of non-"
174                                             "constructor methods", m->line_no);
175                         }
176                 } else if(n->type == VARIABLE_NODE) {
177                         Variable *v = (Variable *)n;
178                         if(strcmp(v->id, "_priv")==0 ||
179                            strcmp(v->id, "__parent__")==0) {
180                                 char *s;
181                                 s = g_strdup_printf("'%s' not allowed as a "
182                                                     "data member name", v->id);
183                                 print_error(FALSE, s, v->line_no);
184                                 g_free(s);
185                         }
186                 }
187         }
188 }
189
190 static void
191 check_duplicate_named(Class *c, Node *node, char *id, int line_no)
192 {
193         GList *l;
194         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
195                 Node *n = l->data;
196                 char *nid;
197                 int nline_no;
198                 char *s;
199                 if(n->type == METHOD_NODE) {
200                         Method *m = (Method *)n;
201                         if(m->method == SIGNAL_LAST_METHOD ||
202                            m->method == SIGNAL_FIRST_METHOD) {
203                                 nid = m->id;
204                                 nline_no = m->line_no;
205                         } else
206                                 continue;
207                 } else if(n->type == ARGUMENT_NODE) {
208                         Argument *a = (Argument *)n;
209                         nid = a->name;
210                         nline_no = a->line_no;
211                 } else
212                         continue;
213                 if(n==node ||
214                    line_no>=nline_no ||
215                    g_strcasecmp(nid,id)!=0)
216                         continue;
217                 s = g_strdup_printf("named symbol (argument or signal) '%s' "
218                                     "redefined, first defined on line %d "
219                                     "(case insensitive)",
220                                     id,line_no);
221                 print_error(FALSE,s,nline_no);
222         }
223 }
224
225 void
226 check_duplicate_signals_args(Class *c)
227 {
228         GList *l;
229         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
230                 Node *n = l->data;
231                 if(n->type == METHOD_NODE) {
232                         Method *m = (Method *)n;
233                         if(m->method == SIGNAL_LAST_METHOD ||
234                            m->method == SIGNAL_FIRST_METHOD)
235                                 check_duplicate_named(c,n,m->id,m->line_no);
236                 } else if(n->type == ARGUMENT_NODE) {
237                         Argument *a = (Argument *)n;
238                         check_duplicate_named(c,n,a->name,a->line_no);
239                 }
240         }
241 }
242
243 void
244 check_public_new(Class *c)
245 {
246         GList *l;
247         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
248                 Node *n = l->data;
249                 if(n->type == METHOD_NODE) {
250                         Method *m = (Method *)n;
251                         if((strcmp(m->id,"new")==0) &&
252                            (m->method != REGULAR_METHOD ||
253                             m->scope != PUBLIC_SCOPE))
254                                 print_error(TRUE,
255                                             "'new' should be a regular\n"
256                                             "public method",
257                                             m->line_no);
258                 }
259         }
260 }
261
262 void
263 check_vararg(Class *c)
264 {
265         GList *l;
266         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
267                 Node *n = l->data;
268                 if(n->type == METHOD_NODE) {
269                         Method *m = (Method *)n;
270                         if(!m->vararg)
271                                 continue;
272                         if(m->method == OVERRIDE_METHOD ||
273                            m->method == SIGNAL_LAST_METHOD ||
274                            m->method == SIGNAL_FIRST_METHOD ||
275                            m->method == VIRTUAL_METHOD) {
276                                 print_error(FALSE,
277                                             "signals, overrides and virtuals, "
278                                             "can't have variable argument "
279                                             "lists",
280                                             m->line_no);
281                         }
282                 }
283         }
284 }
285
286 void
287 check_firstarg(Class *c)
288 {
289         GList *l;
290         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
291                 Node *n = l->data;
292                 if(n->type == METHOD_NODE) {
293                         Method *m = (Method *)n;
294                         if(m->args)
295                                 continue;
296                         if(m->method == OVERRIDE_METHOD ||
297                            m->method == SIGNAL_LAST_METHOD ||
298                            m->method == SIGNAL_FIRST_METHOD ||
299                            m->method == VIRTUAL_METHOD) {
300                                 print_error(FALSE,
301                                             "signals, overrides and virtuals, "
302                                             "can't have no arguments",
303                                             m->line_no);
304                         }
305                 }
306         }
307 }
308
309 void
310 check_nonvoidempty(Class *c)
311 {
312         GList *li;
313         for(li = c->nodes; li != NULL; li = g_list_next(li)) {
314                 Node *n = li->data;
315                 if(n->type == METHOD_NODE) {
316                         Method *m = (Method *)n;
317                         if(m->method != REGULAR_METHOD)
318                                 continue;
319                         if(!(strcmp(m->mtype->name, "void")==0 &&
320                              m->mtype->pointer == NULL) &&
321                            !m->cbuf) {
322                                 print_error(TRUE,
323                                             "non-void empty method found, "
324                                             "regular non-void function should "
325                                             "not be empty.",
326                                             m->line_no);
327                                 /* add a body here, so that the user will also
328                                    get a warning from gcc, and so that it will
329                                    at least point him to the prototype of the
330                                    function in the .gob file */
331                                 m->cbuf = g_strdup("/*empty*/");
332                                 m->ccode_line = m->line_no;
333                         }
334                 }
335         }
336 }
337
338 void
339 check_signal_args(Class *c)
340 {
341         GList *li;
342         for(li = c->nodes; li != NULL; li = g_list_next(li)) {
343                 Node *n = li->data;
344                 if(n->type == METHOD_NODE) {
345                         Method *m = (Method *)n;
346                         GList *l;
347                         if(m->method != SIGNAL_LAST_METHOD &&
348                            m->method != SIGNAL_FIRST_METHOD)
349                                 continue;
350
351                         for(l=m->gtktypes;l;l=l->next) {
352                                 char *s;
353                                 if(get_cast(l->data, FALSE))
354                                         continue;
355                                 s = g_strdup_printf("Unknown GTK+ type '%s' "
356                                                     "among signal types",
357                                                     (char *)l->data);
358                                 print_error(FALSE, s, m->line_no);
359                                 g_free(s);
360                         }
361                 }
362         }
363 }
364
365 void
366 check_argument_types(Class *c)
367 {
368         GList *l;
369         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
370                 Node *n = l->data;
371                 if(n->type == ARGUMENT_NODE) {
372                         Argument *a = (Argument *)n;
373                         char *s;
374                         if(get_cast(a->gtktype, FALSE))
375                                 continue;
376                         s = g_strdup_printf("Unknown GTK+ type '%s' "
377                                             "as argument type",
378                                             a->gtktype);
379                         /* this could perhaps be a warning, but
380                            can there really be a type beyond the
381                            fundementals? */
382                         print_error(FALSE, s, a->line_no);
383                         g_free(s);
384                 }
385         }
386 }
387
388 static void
389 check_func_arg_check_func_arg(Method *m, FuncArg *fa)
390 {
391         GList *li;
392         char *s;
393
394         if( ! fa->checks)
395                 return;
396
397         if(strcmp(fa->atype->name, "void") == 0 &&
398            fa->atype->pointer == NULL) {
399                 print_error(FALSE, "Running checks on a void function "
400                             "argument", m->line_no);
401                 return;
402         }
403         
404         for(li = fa->checks; li; li = g_list_next(li)) {
405                 Check *ch = li->data;
406                 if(ch->chtype == TYPE_CHECK) {
407                         char *p;
408                         gboolean got_type = FALSE;
409                         s = g_strdup(fa->atype->name);
410                         p = strtok(s, " ");
411                         if( ! p) {
412                                 g_free(s);
413                                 goto type_check_error;
414                         }
415                         while(p) {
416                                 if(strcmp(p, "const") != 0) {
417                                         if(got_type) {
418                                                 g_free(s);
419                                                 goto type_check_error;
420                                         }
421                                         got_type = TRUE;
422                                 }
423                                 p = strtok(NULL, " ");
424                         }
425                         g_free(s);
426                         if( ! got_type)
427                                 goto type_check_error;
428
429                         if(fa->atype->pointer == NULL ||
430                            (strcmp(fa->atype->pointer, "*") != 0 &&
431                             strcmp(fa->atype->pointer, "* const") != 0))
432                                 goto type_check_error;
433                 }
434         }
435         return;
436
437 type_check_error:
438         if(fa->atype->pointer)
439                 s = g_strdup_printf("Cannot check the type of '%s %s'",
440                                     fa->atype->name, fa->atype->pointer);
441         else
442                 s = g_strdup_printf("Cannot check the type of '%s'",
443                                     fa->atype->name);
444         print_error(FALSE, s, m->line_no);
445         g_free(s);
446 }
447
448 static void
449 check_func_arg_check_method(Method *m)
450 {
451         GList *li;
452         for(li = m->args; li; li = g_list_next(li)) {
453                 FuncArg *fa = li->data;
454                 check_func_arg_check_func_arg(m, fa);
455         }
456 }
457
458 void
459 check_func_arg_checks(Class *c)
460 {
461         GList *li;
462         for(li = c->nodes; li != NULL; li = g_list_next(li)) {
463                 Node *n = li->data;
464                 if(n->type == METHOD_NODE) {
465                         Method *m = (Method *)n;
466                         check_func_arg_check_method(m);
467                 }
468         }
469 }
470
471 int
472 count_signals(Class *c)
473 {
474         int num = 0;
475         GList *l;
476         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
477                 Node *n = l->data;
478                 if(n->type == METHOD_NODE) {
479                         Method *m = (Method *)n;
480                         if(m->method == SIGNAL_LAST_METHOD ||
481                            m->method == SIGNAL_FIRST_METHOD)
482                                 num++;
483                 }
484         }
485         return num;
486 }
487
488 int
489 count_arguments(Class *c)
490 {
491         int num = 0;
492         GList *li;
493         for(li = c->nodes; li != NULL; li = g_list_next(li)) {
494                 Node *n = li->data;
495                 if(n->type == ARGUMENT_NODE)
496                         num ++;
497         }
498         return num;
499 }
500
501 int
502 count_overrides(Class *c)
503 {
504         int num = 0;
505         GList *l;
506         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
507                 Node *n = l->data;
508                 if(n->type == METHOD_NODE) {
509                         Method *m = (Method *)n;
510                         if(m->method == OVERRIDE_METHOD)
511                                 num++;
512                 }
513         }
514         return num;
515 }
516
517 int
518 count_privates(Class *c)
519 {
520         int num = 0;
521         GList *l;
522         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
523                 Node *n = l->data;
524                 if(n->type == VARIABLE_NODE) {
525                         Variable *v = (Variable *)n;
526                         if(v->scope == PRIVATE_SCOPE)
527                                 num++;
528                 }
529         }
530         return num;
531 }
532
533 int
534 count_protecteds(Class *c)
535 {
536         int num = 0;
537         GList *l;
538         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
539                 Node *n = l->data;
540                 if(n->type == METHOD_NODE) {
541                         Method *m = (Method *)n;
542                         if(m->scope == PROTECTED_SCOPE)
543                                 num++;
544                 }
545         }
546         return num;
547 }
548
549 int
550 count_destructors(Class *c)
551 {
552         int num = 0;
553         GList *l;
554         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
555                 Node *n = l->data;
556                 if(n->type == VARIABLE_NODE) {
557                         Variable *v = (Variable *)n;
558                         if(v->destructor)
559                                 num++;
560                 }
561         }
562         return num;
563 }
564
565 int
566 count_initializers(Class *c)
567 {
568         int num = 0;
569         GList *l;
570         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
571                 Node *n = l->data;
572                 if(n->type == VARIABLE_NODE) {
573                         Variable *v = (Variable *)n;
574                         if(v->initializer)
575                                 num++;
576                 }
577         }
578         return num;
579 }