/* GOB C Preprocessor * Copyright (C) 1999-2000 the Free Software Foundation. * * Author: George Lebl * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "config.h" #include #include #include #include "tree.h" #include "main.h" #include "util.h" #include "checks.h" void check_duplicate(Class *c, Node *node, char *id, int line_no) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; char *nid; int nline_no; char *s; if(n->type == METHOD_NODE) { Method *m = (Method *)n; nid = m->id; nline_no = m->line_no; } else if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; nid = v->id; nline_no = v->line_no; } else continue; if(n==node || line_no>=nline_no || strcmp(nid,id)!=0 || n->type != node->type) continue; s = g_strdup_printf("symbol '%s' redefined, " "first defined on line %d", id,line_no); print_error(FALSE,s,nline_no); } } void check_duplicate_symbols(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; check_duplicate(c,n,m->id,m->line_no); } else if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; check_duplicate(c,n,v->id,v->line_no); } } } void check_bad_symbols(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if((m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD || m->method == VIRTUAL_METHOD) && strcmp(m->id,"__parent__")==0) { char *s; s = g_strdup_printf("'%s' not allowed as an " "identifier of signal " "or virtual methods", m->id); print_error(FALSE,s,m->line_no); g_free(s); } if(m->method != INIT_METHOD && m->method != CLASS_INIT_METHOD && (strcmp(m->id,"init")==0 || strcmp(m->id,"class_init")==0)) { print_error(FALSE,"init, or class_init not " "allowed as an " "identifier of non-" "constructor methods",m->line_no); } } else if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; if(strcmp(v->id,"_priv")==0 || strcmp(v->id,"__parent__")==0) { char *s; s = g_strdup_printf("'%s' not allowed as a " "data member name",v->id); print_error(FALSE,s,v->line_no); g_free(s); } } } } void check_duplicate_named(Class *c,Node *node,char *id, int line_no) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; char *nid; int nline_no; char *s; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD) { nid = m->id; nline_no = m->line_no; } else continue; } else if(n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; nid = a->name; nline_no = a->line_no; } else continue; if(n==node || line_no>=nline_no || strcmp(nid,id)!=0) continue; s = g_strdup_printf("named symbol (argument or signal) '%s' " "redefined, first defined on line %d", id,line_no); print_error(FALSE,s,nline_no); } } void check_duplicate_signals_args(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD) check_duplicate_named(c,n,m->id,m->line_no); } else if(n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; check_duplicate_named(c,n,a->name,a->line_no); } } } void check_public_new(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if((strcmp(m->id,"new")==0) && (m->method != REGULAR_METHOD || m->scope != PUBLIC_SCOPE)) print_error(TRUE, "'new' should be a regular\n" "public method", m->line_no); } } } void check_vararg(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(!m->vararg) continue; if(m->method == OVERRIDE_METHOD || m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD || m->method == VIRTUAL_METHOD) { print_error(FALSE, "signals, overrides and virtuals, " "can't have variable argument " "lists", m->line_no); } } } } void check_firstarg(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->args) continue; if(m->method == OVERRIDE_METHOD || m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD || m->method == VIRTUAL_METHOD) { print_error(FALSE, "signals, overrides and virtuals, " "can't have no arguments", m->line_no); } } } } void check_nonvoidempty(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method != REGULAR_METHOD) continue; if(!(strcmp(m->mtype->name,"void")==0 && m->mtype->stars == 0) && !m->cbuf) { print_error(TRUE, "non-void empty method found, " "regular non-void function should " "not be empty.", m->line_no); /* add a body here, so that the user will also get a warning from gcc, and so that it will at least point him to the prototype of the function in the .gob file */ m->cbuf = g_strdup("/*empty*/"); m->ccode_line = m->line_no; } } } } void check_signal_args(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; GList *l; if(m->method != SIGNAL_LAST_METHOD && m->method != SIGNAL_FIRST_METHOD) continue; for(l=m->gtktypes;l;l=l->next) { char *s; if(get_cast(l->data,FALSE)) continue; s = g_strdup_printf("Unknown GTK+ type '%s' " "among signal types", (char *)l->data); print_error(FALSE, s, m->line_no); g_free(s); } } } } void check_argument_types(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; char *s; if(get_cast(a->gtktype,FALSE)) continue; s = g_strdup_printf("Unknown GTK+ type '%s' " "as argument type", a->gtktype); /* this could perhaps be a warning, but can there really be a type beyond the fundementals? */ print_error(FALSE, s, a->line_no); g_free(s); } } } int count_signals(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD) num++; } } return num; } int count_arguments(Class *c) { int num = 0; GList *li; for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; if(n->type == ARGUMENT_NODE) num ++; } return num; } int count_overrides(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == OVERRIDE_METHOD) num++; } } return num; } int count_privates(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; if(v->scope == PRIVATE_SCOPE) num++; } } return num; } int count_protecteds(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->scope == PROTECTED_SCOPE) num++; } } return num; } int count_destructors(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; if(v->destructor) num++; } } return num; } int count_initializers(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; if(v->initializer) num++; } } return num; }