]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
8bbe1e4ee07ae94321980f65bd17a6ae6e32e250
[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                             strcmp(fa->atype->pointer, "const *") != 0))
433                                 goto type_check_error;
434                 }
435         }
436         return;
437
438 type_check_error:
439         if(fa->atype->pointer)
440                 s = g_strdup_printf("Cannot check the type of '%s %s'",
441                                     fa->atype->name, fa->atype->pointer);
442         else
443                 s = g_strdup_printf("Cannot check the type of '%s'",
444                                     fa->atype->name);
445         print_error(FALSE, s, m->line_no);
446         g_free(s);
447 }
448
449 static void
450 check_func_arg_check_method(Method *m)
451 {
452         GList *li;
453         for(li = m->args; li; li = g_list_next(li)) {
454                 FuncArg *fa = li->data;
455                 check_func_arg_check_func_arg(m, fa);
456         }
457 }
458
459 void
460 check_func_arg_checks(Class *c)
461 {
462         GList *li;
463         for(li = c->nodes; li != NULL; li = g_list_next(li)) {
464                 Node *n = li->data;
465                 if(n->type == METHOD_NODE) {
466                         Method *m = (Method *)n;
467                         check_func_arg_check_method(m);
468                 }
469         }
470 }
471
472 int
473 count_signals(Class *c)
474 {
475         int num = 0;
476         GList *l;
477         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
478                 Node *n = l->data;
479                 if(n->type == METHOD_NODE) {
480                         Method *m = (Method *)n;
481                         if(m->method == SIGNAL_LAST_METHOD ||
482                            m->method == SIGNAL_FIRST_METHOD)
483                                 num++;
484                 }
485         }
486         return num;
487 }
488
489 int
490 count_arguments(Class *c)
491 {
492         int num = 0;
493         GList *li;
494         for(li = c->nodes; li != NULL; li = g_list_next(li)) {
495                 Node *n = li->data;
496                 if(n->type == ARGUMENT_NODE)
497                         num ++;
498         }
499         return num;
500 }
501
502 int
503 count_overrides(Class *c)
504 {
505         int num = 0;
506         GList *l;
507         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
508                 Node *n = l->data;
509                 if(n->type == METHOD_NODE) {
510                         Method *m = (Method *)n;
511                         if(m->method == OVERRIDE_METHOD)
512                                 num++;
513                 }
514         }
515         return num;
516 }
517
518 int
519 count_privates(Class *c)
520 {
521         int num = 0;
522         GList *l;
523         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
524                 Node *n = l->data;
525                 if(n->type == VARIABLE_NODE) {
526                         Variable *v = (Variable *)n;
527                         if(v->scope == PRIVATE_SCOPE)
528                                 num++;
529                 }
530         }
531         return num;
532 }
533
534 int
535 count_protecteds(Class *c)
536 {
537         int num = 0;
538         GList *l;
539         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
540                 Node *n = l->data;
541                 if(n->type == METHOD_NODE) {
542                         Method *m = (Method *)n;
543                         if(m->scope == PROTECTED_SCOPE)
544                                 num++;
545                 }
546         }
547         return num;
548 }
549
550 int
551 count_destructors(Class *c)
552 {
553         int num = 0;
554         GList *l;
555         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
556                 Node *n = l->data;
557                 if(n->type == VARIABLE_NODE) {
558                         Variable *v = (Variable *)n;
559                         if(v->destructor)
560                                 num++;
561                 }
562         }
563         return num;
564 }
565
566 int
567 count_initializers(Class *c)
568 {
569         int num = 0;
570         GList *l;
571         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
572                 Node *n = l->data;
573                 if(n->type == VARIABLE_NODE) {
574                         Variable *v = (Variable *)n;
575                         if(v->initializer)
576                                 num++;
577                 }
578         }
579         return num;
580 }