]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
Release 0.93.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, 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->stars == 0) &&
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 int
389 count_signals(Class *c)
390 {
391         int num = 0;
392         GList *l;
393         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
394                 Node *n = l->data;
395                 if(n->type == METHOD_NODE) {
396                         Method *m = (Method *)n;
397                         if(m->method == SIGNAL_LAST_METHOD ||
398                            m->method == SIGNAL_FIRST_METHOD)
399                                 num++;
400                 }
401         }
402         return num;
403 }
404
405 int
406 count_arguments(Class *c)
407 {
408         int num = 0;
409         GList *li;
410         for(li = c->nodes; li != NULL; li = g_list_next(li)) {
411                 Node *n = li->data;
412                 if(n->type == ARGUMENT_NODE)
413                         num ++;
414         }
415         return num;
416 }
417
418 int
419 count_overrides(Class *c)
420 {
421         int num = 0;
422         GList *l;
423         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
424                 Node *n = l->data;
425                 if(n->type == METHOD_NODE) {
426                         Method *m = (Method *)n;
427                         if(m->method == OVERRIDE_METHOD)
428                                 num++;
429                 }
430         }
431         return num;
432 }
433
434 int
435 count_privates(Class *c)
436 {
437         int num = 0;
438         GList *l;
439         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
440                 Node *n = l->data;
441                 if(n->type == VARIABLE_NODE) {
442                         Variable *v = (Variable *)n;
443                         if(v->scope == PRIVATE_SCOPE)
444                                 num++;
445                 }
446         }
447         return num;
448 }
449
450 int
451 count_protecteds(Class *c)
452 {
453         int num = 0;
454         GList *l;
455         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
456                 Node *n = l->data;
457                 if(n->type == METHOD_NODE) {
458                         Method *m = (Method *)n;
459                         if(m->scope == PROTECTED_SCOPE)
460                                 num++;
461                 }
462         }
463         return num;
464 }
465
466 int
467 count_destructors(Class *c)
468 {
469         int num = 0;
470         GList *l;
471         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
472                 Node *n = l->data;
473                 if(n->type == VARIABLE_NODE) {
474                         Variable *v = (Variable *)n;
475                         if(v->destructor)
476                                 num++;
477                 }
478         }
479         return num;
480 }
481
482 int
483 count_initializers(Class *c)
484 {
485         int num = 0;
486         GList *l;
487         for(l = c->nodes; l != NULL; l = g_list_next(l)) {
488                 Node *n = l->data;
489                 if(n->type == VARIABLE_NODE) {
490                         Variable *v = (Variable *)n;
491                         if(v->initializer)
492                                 num++;
493                 }
494         }
495         return num;
496 }