]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
d287341513dc34c21903e97b1b3558eed787cca9
[gob-dx.git] / src / checks.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999-2000 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the  Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  * USA.
20  */
21
22 #include "config.h"
23 #include <string.h>
24 #include <stdio.h>
25 #include <glib.h>
26
27 #include "treefuncs.h"
28 #include "main.h"
29 #include "util.h"
30
31 #include "checks.h"
32
33 void
34 check_duplicate(Class *c, Node *node, char *id, int line_no)
35 {
36         GList *l;
37         for(l=c->nodes;l;l=g_list_next(l)) {
38                 Node *n = l->data;
39                 char *nid;
40                 int nline_no;
41                 char *s;
42                 if(n->type == METHOD_NODE) {
43                         Method *m = (Method *)n;
44                         nid = m->id;
45                         nline_no = m->line_no;
46                 } else if(n->type == VARIABLE_NODE) {
47                         Variable *v = (Variable *)n;
48                         nid = v->id;
49                         nline_no = v->line_no;
50                 } else
51                         continue;
52                 if(n==node ||
53                    line_no>=nline_no ||
54                    strcmp(nid,id)!=0 ||
55                    n->type != node->type)
56                         continue;
57                 s = g_strdup_printf("symbol '%s' redefined, "
58                                     "first defined on line %d",
59                                     id,line_no);
60                 print_error(FALSE,s,nline_no);
61         }
62 }
63
64 void
65 check_duplicate_symbols(Class *c)
66 {
67         GList *l;
68         for(l=c->nodes;l;l=g_list_next(l)) {
69                 Node *n = l->data;
70                 if(n->type == METHOD_NODE) {
71                         Method *m = (Method *)n;
72                         check_duplicate(c,n,m->id,m->line_no);
73                 } else if(n->type == VARIABLE_NODE) {
74                         Variable *v = (Variable *)n;
75                         check_duplicate(c,n,v->id,v->line_no);
76                 }
77         }
78 }
79
80 void
81 check_bad_symbols(Class *c)
82 {
83         GList *l;
84         for(l=c->nodes;l;l=g_list_next(l)) {
85                 Node *n = l->data;
86                 if(n->type == METHOD_NODE) {
87                         Method *m = (Method *)n;
88                         if((m->method == SIGNAL_LAST_METHOD ||
89                             m->method == SIGNAL_FIRST_METHOD ||
90                             m->method == VIRTUAL_METHOD) &&
91                            strcmp(m->id,"__parent__")==0) {
92                                 char *s;
93                                 s = g_strdup_printf("'%s' not allowed as an "
94                                                     "identifier of signal "
95                                                     "or virtual methods",
96                                                     m->id);
97                                 print_error(FALSE,s,m->line_no);
98                                 g_free(s);
99                         }
100                         if(m->method != INIT_METHOD &&
101                            m->method != CLASS_INIT_METHOD &&
102                            (strcmp(m->id,"init")==0 ||
103                             strcmp(m->id,"class_init")==0)) {
104                                 print_error(FALSE,"init, or class_init not "
105                                             "allowed as an "
106                                             "identifier of non-"
107                                             "constructor methods",m->line_no);
108                         }
109                 } else if(n->type == VARIABLE_NODE) {
110                         Variable *v = (Variable *)n;
111                         if(strcmp(v->id,"_priv")==0 ||
112                            strcmp(v->id,"__parent__")==0) {
113                                 char *s;
114                                 s = g_strdup_printf("'%s' not allowed as a "
115                                                     "data member name",v->id);
116                                 print_error(FALSE,s,v->line_no);
117                                 g_free(s);
118                         }
119                 }
120         }
121 }
122
123
124 void
125 check_duplicate_named(Class *c,Node *node,char *id, int line_no)
126 {
127         GList *l;
128         for(l=c->nodes;l;l=g_list_next(l)) {
129                 Node *n = l->data;
130                 char *nid;
131                 int nline_no;
132                 char *s;
133                 if(n->type == METHOD_NODE) {
134                         Method *m = (Method *)n;
135                         if(m->method == SIGNAL_LAST_METHOD ||
136                            m->method == SIGNAL_FIRST_METHOD) {
137                                 nid = m->id;
138                                 nline_no = m->line_no;
139                         } else
140                                 continue;
141                 } else if(n->type == ARGUMENT_NODE) {
142                         Argument *a = (Argument *)n;
143                         nid = a->name;
144                         nline_no = a->line_no;
145                 } else
146                         continue;
147                 if(n==node ||
148                    line_no>=nline_no ||
149                    g_strcasecmp(nid,id)!=0)
150                         continue;
151                 s = g_strdup_printf("named symbol (argument or signal) '%s' "
152                                     "redefined, first defined on line %d "
153                                     "(case insensitive)",
154                                     id,line_no);
155                 print_error(FALSE,s,nline_no);
156         }
157 }
158
159 void
160 check_duplicate_signals_args(Class *c)
161 {
162         GList *l;
163         for(l=c->nodes;l;l=g_list_next(l)) {
164                 Node *n = l->data;
165                 if(n->type == METHOD_NODE) {
166                         Method *m = (Method *)n;
167                         if(m->method == SIGNAL_LAST_METHOD ||
168                            m->method == SIGNAL_FIRST_METHOD)
169                                 check_duplicate_named(c,n,m->id,m->line_no);
170                 } else if(n->type == ARGUMENT_NODE) {
171                         Argument *a = (Argument *)n;
172                         check_duplicate_named(c,n,a->name,a->line_no);
173                 }
174         }
175 }
176
177 void
178 check_public_new(Class *c)
179 {
180         GList *l;
181         for(l=c->nodes;l;l=g_list_next(l)) {
182                 Node *n = l->data;
183                 if(n->type == METHOD_NODE) {
184                         Method *m = (Method *)n;
185                         if((strcmp(m->id,"new")==0) &&
186                            (m->method != REGULAR_METHOD ||
187                             m->scope != PUBLIC_SCOPE))
188                                 print_error(TRUE,
189                                             "'new' should be a regular\n"
190                                             "public method",
191                                             m->line_no);
192                 }
193         }
194 }
195
196 void
197 check_vararg(Class *c)
198 {
199         GList *l;
200         for(l=c->nodes;l;l=g_list_next(l)) {
201                 Node *n = l->data;
202                 if(n->type == METHOD_NODE) {
203                         Method *m = (Method *)n;
204                         if(!m->vararg)
205                                 continue;
206                         if(m->method == OVERRIDE_METHOD ||
207                            m->method == SIGNAL_LAST_METHOD ||
208                            m->method == SIGNAL_FIRST_METHOD ||
209                            m->method == VIRTUAL_METHOD) {
210                                 print_error(FALSE,
211                                             "signals, overrides and virtuals, "
212                                             "can't have variable argument "
213                                             "lists",
214                                             m->line_no);
215                         }
216                 }
217         }
218 }
219
220 void
221 check_firstarg(Class *c)
222 {
223         GList *l;
224         for(l=c->nodes;l;l=g_list_next(l)) {
225                 Node *n = l->data;
226                 if(n->type == METHOD_NODE) {
227                         Method *m = (Method *)n;
228                         if(m->args)
229                                 continue;
230                         if(m->method == OVERRIDE_METHOD ||
231                            m->method == SIGNAL_LAST_METHOD ||
232                            m->method == SIGNAL_FIRST_METHOD ||
233                            m->method == VIRTUAL_METHOD) {
234                                 print_error(FALSE,
235                                             "signals, overrides and virtuals, "
236                                             "can't have no arguments",
237                                             m->line_no);
238                         }
239                 }
240         }
241 }
242
243 void
244 check_nonvoidempty(Class *c)
245 {
246         GList *li;
247         for(li=c->nodes; li; li=g_list_next(li)) {
248                 Node *n = li->data;
249                 if(n->type == METHOD_NODE) {
250                         Method *m = (Method *)n;
251                         if(m->method != REGULAR_METHOD)
252                                 continue;
253                         if(!(strcmp(m->mtype->name, "void")==0 &&
254                              m->mtype->stars == 0) &&
255                            !m->cbuf) {
256                                 print_error(TRUE,
257                                             "non-void empty method found, "
258                                             "regular non-void function should "
259                                             "not be empty.",
260                                             m->line_no);
261                                 /* add a body here, so that the user will also
262                                    get a warning from gcc, and so that it will
263                                    at least point him to the prototype of the
264                                    function in the .gob file */
265                                 m->cbuf = g_strdup("/*empty*/");
266                                 m->ccode_line = m->line_no;
267                         }
268                 }
269         }
270 }
271
272 void
273 check_signal_args(Class *c)
274 {
275         GList *li;
276         for(li=c->nodes; li; li=g_list_next(li)) {
277                 Node *n = li->data;
278                 if(n->type == METHOD_NODE) {
279                         Method *m = (Method *)n;
280                         GList *l;
281                         if(m->method != SIGNAL_LAST_METHOD &&
282                            m->method != SIGNAL_FIRST_METHOD)
283                                 continue;
284
285                         for(l=m->gtktypes;l;l=l->next) {
286                                 char *s;
287                                 if(get_cast(l->data, FALSE))
288                                         continue;
289                                 s = g_strdup_printf("Unknown GTK+ type '%s' "
290                                                     "among signal types",
291                                                     (char *)l->data);
292                                 print_error(FALSE, s, m->line_no);
293                                 g_free(s);
294                         }
295                 }
296         }
297 }
298
299 void
300 check_argument_types(Class *c)
301 {
302         GList *l;
303         for(l=c->nodes;l;l=g_list_next(l)) {
304                 Node *n = l->data;
305                 if(n->type == ARGUMENT_NODE) {
306                         Argument *a = (Argument *)n;
307                         char *s;
308                         if(get_cast(a->gtktype, FALSE))
309                                 continue;
310                         s = g_strdup_printf("Unknown GTK+ type '%s' "
311                                             "as argument type",
312                                             a->gtktype);
313                         /* this could perhaps be a warning, but
314                            can there really be a type beyond the
315                            fundementals? */
316                         print_error(FALSE, s, a->line_no);
317                         g_free(s);
318                 }
319         }
320 }
321
322 int
323 count_signals(Class *c)
324 {
325         int num = 0;
326         GList *l;
327         for(l=c->nodes;l;l=g_list_next(l)) {
328                 Node *n = l->data;
329                 if(n->type == METHOD_NODE) {
330                         Method *m = (Method *)n;
331                         if(m->method == SIGNAL_LAST_METHOD ||
332                            m->method == SIGNAL_FIRST_METHOD)
333                                 num++;
334                 }
335         }
336         return num;
337 }
338
339 int
340 count_arguments(Class *c)
341 {
342         int num = 0;
343         GList *li;
344
345         for(li=c->nodes;li;li=g_list_next(li)) {
346                 Node *n = li->data;
347                 if(n->type == ARGUMENT_NODE)
348                         num ++;
349         }
350         return num;
351 }
352
353 int
354 count_overrides(Class *c)
355 {
356         int num = 0;
357         GList *l;
358         for(l=c->nodes;l;l=g_list_next(l)) {
359                 Node *n = l->data;
360                 if(n->type == METHOD_NODE) {
361                         Method *m = (Method *)n;
362                         if(m->method == OVERRIDE_METHOD)
363                                 num++;
364                 }
365         }
366         return num;
367 }
368
369 int
370 count_privates(Class *c)
371 {
372         int num = 0;
373         GList *l;
374         for(l=c->nodes;l;l=g_list_next(l)) {
375                 Node *n = l->data;
376                 if(n->type == VARIABLE_NODE) {
377                         Variable *v = (Variable *)n;
378                         if(v->scope == PRIVATE_SCOPE)
379                                 num++;
380                 }
381         }
382         return num;
383 }
384
385 int
386 count_protecteds(Class *c)
387 {
388         int num = 0;
389         GList *l;
390         for(l=c->nodes;l;l=g_list_next(l)) {
391                 Node *n = l->data;
392                 if(n->type == METHOD_NODE) {
393                         Method *m = (Method *)n;
394                         if(m->scope == PROTECTED_SCOPE)
395                                 num++;
396                 }
397         }
398         return num;
399 }
400
401 int
402 count_destructors(Class *c)
403 {
404         int num = 0;
405         GList *l;
406         for(l=c->nodes;l;l=g_list_next(l)) {
407                 Node *n = l->data;
408                 if(n->type == VARIABLE_NODE) {
409                         Variable *v = (Variable *)n;
410                         if(v->destructor)
411                                 num++;
412                 }
413         }
414         return num;
415 }
416
417 int
418 count_initializers(Class *c)
419 {
420         int num = 0;
421         GList *l;
422         for(l=c->nodes;l;l=g_list_next(l)) {
423                 Node *n = l->data;
424                 if(n->type == VARIABLE_NODE) {
425                         Variable *v = (Variable *)n;
426                         if(v->initializer)
427                                 num++;
428                 }
429         }
430         return num;
431 }