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