]> git.draconx.ca Git - gob-dx.git/blob - src/checks.c
Release 0.92.2
[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 "tree.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                    strcmp(nid,id)!=0)
150                         continue;
151                 s = g_strdup_printf("named symbol (argument or signal) '%s' "
152                                     "redefined, first defined on line %d",
153                                     id,line_no);
154                 print_error(FALSE,s,nline_no);
155         }
156 }
157
158 void
159 check_duplicate_signals_args(Class *c)
160 {
161         GList *l;
162         for(l=c->nodes;l;l=g_list_next(l)) {
163                 Node *n = l->data;
164                 if(n->type == METHOD_NODE) {
165                         Method *m = (Method *)n;
166                         if(m->method == SIGNAL_LAST_METHOD ||
167                            m->method == SIGNAL_FIRST_METHOD)
168                                 check_duplicate_named(c,n,m->id,m->line_no);
169                 } else if(n->type == ARGUMENT_NODE) {
170                         Argument *a = (Argument *)n;
171                         check_duplicate_named(c,n,a->name,a->line_no);
172                 }
173         }
174 }
175
176 void
177 check_public_new(Class *c)
178 {
179         GList *l;
180         for(l=c->nodes;l;l=g_list_next(l)) {
181                 Node *n = l->data;
182                 if(n->type == METHOD_NODE) {
183                         Method *m = (Method *)n;
184                         if((strcmp(m->id,"new")==0) &&
185                            (m->method != REGULAR_METHOD ||
186                             m->scope != PUBLIC_SCOPE))
187                                 print_error(TRUE,
188                                             "'new' should be a regular\n"
189                                             "public method",
190                                             m->line_no);
191                 }
192         }
193 }
194
195 void
196 check_vararg(Class *c)
197 {
198         GList *l;
199         for(l=c->nodes;l;l=g_list_next(l)) {
200                 Node *n = l->data;
201                 if(n->type == METHOD_NODE) {
202                         Method *m = (Method *)n;
203                         if(!m->vararg)
204                                 continue;
205                         if(m->method == OVERRIDE_METHOD ||
206                            m->method == SIGNAL_LAST_METHOD ||
207                            m->method == SIGNAL_FIRST_METHOD ||
208                            m->method == VIRTUAL_METHOD) {
209                                 print_error(FALSE,
210                                             "signals, overrides and virtuals, "
211                                             "can't have variable argument "
212                                             "lists",
213                                             m->line_no);
214                         }
215                 }
216         }
217 }
218
219 void
220 check_firstarg(Class *c)
221 {
222         GList *l;
223         for(l=c->nodes;l;l=g_list_next(l)) {
224                 Node *n = l->data;
225                 if(n->type == METHOD_NODE) {
226                         Method *m = (Method *)n;
227                         if(m->args)
228                                 continue;
229                         if(m->method == OVERRIDE_METHOD ||
230                            m->method == SIGNAL_LAST_METHOD ||
231                            m->method == SIGNAL_FIRST_METHOD ||
232                            m->method == VIRTUAL_METHOD) {
233                                 print_error(FALSE,
234                                             "signals, overrides and virtuals, "
235                                             "can't have no arguments",
236                                             m->line_no);
237                         }
238                 }
239         }
240 }
241
242 void
243 check_nonvoidempty(Class *c)
244 {
245         GList *l;
246         for(l=c->nodes;l;l=g_list_next(l)) {
247                 Node *n = l->data;
248                 if(n->type == METHOD_NODE) {
249                         Method *m = (Method *)n;
250                         if(m->method != REGULAR_METHOD)
251                                 continue;
252                         if(!(strcmp(m->mtype->name,"void")==0 &&
253                              m->mtype->stars == 0) &&
254                            !m->cbuf) {
255                                 print_error(TRUE,
256                                             "non-void empty method found, "
257                                             "regular non-void function should "
258                                             "not be empty.",
259                                             m->line_no);
260                                 /* add a body here, so that the user will also
261                                    get a warning from gcc, and so that it will
262                                    at least point him to the prototype of the
263                                    function in the .gob file */
264                                 m->cbuf = g_strdup("/*empty*/");
265                                 m->ccode_line = m->line_no;
266                         }
267                 }
268         }
269 }
270
271 void
272 check_signal_args(Class *c)
273 {
274         GList *l;
275         for(l=c->nodes;l;l=g_list_next(l)) {
276                 Node *n = l->data;
277                 if(n->type == METHOD_NODE) {
278                         Method *m = (Method *)n;
279                         GList *l;
280                         if(m->method != SIGNAL_LAST_METHOD &&
281                            m->method != SIGNAL_FIRST_METHOD)
282                                 continue;
283
284                         for(l=m->gtktypes;l;l=l->next) {
285                                 char *s;
286                                 if(get_cast(l->data,FALSE))
287                                         continue;
288                                 s = g_strdup_printf("Unknown GTK+ type '%s' "
289                                                     "among signal types",
290                                                     (char *)l->data);
291                                 print_error(FALSE, s, m->line_no);
292                                 g_free(s);
293                         }
294                 }
295         }
296 }
297
298 void
299 check_argument_types(Class *c)
300 {
301         GList *l;
302         for(l=c->nodes;l;l=g_list_next(l)) {
303                 Node *n = l->data;
304                 if(n->type == ARGUMENT_NODE) {
305                         Argument *a = (Argument *)n;
306                         char *s;
307                         if(get_cast(a->gtktype,FALSE))
308                                 continue;
309                         s = g_strdup_printf("Unknown GTK+ type '%s' "
310                                             "as argument type",
311                                             a->gtktype);
312                         /* this could perhaps be a warning, but
313                            can there really be a type beyond the
314                            fundementals? */
315                         print_error(FALSE, s, a->line_no);
316                         g_free(s);
317                 }
318         }
319 }
320
321 int
322 count_signals(Class *c)
323 {
324         int num = 0;
325         GList *l;
326         for(l=c->nodes;l;l=g_list_next(l)) {
327                 Node *n = l->data;
328                 if(n->type == METHOD_NODE) {
329                         Method *m = (Method *)n;
330                         if(m->method == SIGNAL_LAST_METHOD ||
331                            m->method == SIGNAL_FIRST_METHOD)
332                                 num++;
333                 }
334         }
335         return num;
336 }
337
338 int
339 count_arguments(Class *c)
340 {
341         int num = 0;
342         GList *li;
343
344         for(li=c->nodes;li;li=g_list_next(li)) {
345                 Node *n = li->data;
346                 if(n->type == ARGUMENT_NODE)
347                         num ++;
348         }
349         return num;
350 }
351
352 int
353 count_overrides(Class *c)
354 {
355         int num = 0;
356         GList *l;
357         for(l=c->nodes;l;l=g_list_next(l)) {
358                 Node *n = l->data;
359                 if(n->type == METHOD_NODE) {
360                         Method *m = (Method *)n;
361                         if(m->method == OVERRIDE_METHOD)
362                                 num++;
363                 }
364         }
365         return num;
366 }
367
368 int
369 count_privates(Class *c)
370 {
371         int num = 0;
372         GList *l;
373         for(l=c->nodes;l;l=g_list_next(l)) {
374                 Node *n = l->data;
375                 if(n->type == VARIABLE_NODE) {
376                         Variable *v = (Variable *)n;
377                         if(v->scope == PRIVATE_SCOPE)
378                                 num++;
379                 }
380         }
381         return num;
382 }
383
384 int
385 count_protecteds(Class *c)
386 {
387         int num = 0;
388         GList *l;
389         for(l=c->nodes;l;l=g_list_next(l)) {
390                 Node *n = l->data;
391                 if(n->type == METHOD_NODE) {
392                         Method *m = (Method *)n;
393                         if(m->scope == PROTECTED_SCOPE)
394                                 num++;
395                 }
396         }
397         return num;
398 }