Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / lint / lpass2 / lpass2.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 /* $Id: lpass2.c,v 1.10 1994/06/24 12:25:48 ceriel Exp $ */
6
7 #include        <alloc.h>
8
9 #include        "private.h"
10 #include        "l_lint.h"
11 #include        "l_class.h"
12 #include        "class.h"
13 #include        "inpdef.h"
14
15 extern char *strcpy();
16
17 #define streq(s1,s2)    (strcmp(s1, s2) == 0)
18
19 PRIVATE char cur_name[NAMESIZE];
20 PRIVATE struct inpdef *dot, *lib, *proto, *ext, *sta;
21
22 PRIVATE one_name();
23 PRIVATE chk_def();
24 PRIVATE ext_decls();
25 PRIVATE proto_defs();
26 PRIVATE chk_proto();
27 PRIVATE ext_def();
28 PRIVATE get_dot();
29 PRIVATE init();
30 PRIVATE lib_def();
31 PRIVATE one_ext_decl();
32 PRIVATE one_func_call();
33 PRIVATE one_var_usage();
34 PRIVATE stat_def();
35 PRIVATE statics();
36 PRIVATE usage();
37
38 #define same_name()     (dot && streq(cur_name, dot->id_name))
39 #define same_obj(stnr)  (same_name() && dot->id_statnr == stnr)
40
41 #define def_or_dec(id)  (is_class(id, CL_DEF) ? "defined" : "declared")
42 #define fun_or_var(id)  (is_class(id, CL_FUNC) ? "function" : "variable")
43
44
45 /******** M A I N ********/
46
47 main(argc, argv)
48         char *argv[];
49 {
50         init(argc, argv);
51
52         dot = new_inpdef();
53         get_dot();
54         while (dot) {
55                 if (lib) {
56                         free_inpdef(lib);
57                         lib = 0;
58                 }
59                 if (proto) {
60                         free_inpdef(proto);
61                         proto = 0;
62                 }
63                 if (ext) {
64                         free_inpdef(ext);
65                         ext = 0;
66                 }
67                 one_name();
68         }
69 }
70
71 char loptions[128];
72 static char *table[] = {0};
73
74 PRIVATE init(argc, argv)
75         char *argv[];
76 {
77 /*
78  * Get command line options
79  * Prepare standard input for reading using the input-package
80  */
81         char *result;
82
83         init_class();
84
85         while (argc > 1 && argv[1][0] == '-') {
86                 register char *arg = &argv[1][1];
87                 register char ch;
88
89                 while (ch = *arg++) {
90                         switch (ch) {
91                         case 'u':
92                                 /*      don't report situations like
93                                         "not used anywhere"
94                                 */
95                         case 'X':       /* ??? prints incoming inpdefs */
96                         default:        /* and any other */
97                                 loptions[ch] = 1;
98                                 break;
99                         }
100                 }
101                 argc--, argv++;
102         }
103
104         if (!InsertFile((char *)0, table, &result)) {
105                 panic("InsertFile() fails");
106         }
107 }
108
109 PRIVATE get_dot()
110 {
111         if (!get_id(dot)) {
112                 free_inpdef(dot);
113                 dot = 0;
114                 cur_name[0] = '\0';
115         }
116         if (loptions['X']) {
117                 print_id("get_dot", dot);
118         }
119 }
120
121 PRIVATE one_name()
122 {
123         strcpy(cur_name, dot->id_name);
124         lib_def();
125         proto_defs();
126         ext_def();
127         ext_decls();
128         usage(0);
129         if (proto) {
130                 chk_def(proto);
131         }
132         else
133         if (ext) {
134                 chk_def(ext);
135         }
136         statics();
137         if (same_name()) {
138                 /* there are lines for this name that have not been absorbed */
139                 panic("sequence error in intermediate file");
140         }
141 }
142
143 /******** L I B R A R Y ********/
144
145 PRIVATE lib_def()
146 {
147         if (same_obj(0) && is_class(dot, CL_LIB)) {
148                 lib = dot;
149                 dot = new_inpdef();
150                 get_dot();
151                 while (same_obj(0) && is_class(dot, CL_LIB)) {
152                         report(">%L: multiple definition of %s in library",
153                                 dot, dot->id_name);
154                         get_dot();
155                 }
156         }
157 }
158
159
160 /******** P R O T O T Y P E S ********/
161 PRIVATE proto_defs()
162 {
163         if (same_obj(0) && dot->id_class == PFDF) {
164                 if (lib) {
165                         report("%L: function %s also defined in %L",
166                                 dot, dot->id_name, lib);
167                 }
168                 proto = dot;
169                 dot = new_inpdef();
170                 get_dot();
171                 while (same_obj(0) && dot->id_class == PFDF) {
172                         chk_proto(dot);
173                         get_dot();
174                 }
175         }
176 }
177
178 PRIVATE chk_proto(def)
179         struct inpdef *def;
180 {
181         if (proto->id_args) {
182                 chk_args(def, proto);
183         }
184         if (!type_equal(def->id_type, proto->id_type)) {
185                 report("%L: return type of function %s declared differently at %L",
186                         def, def->id_name, proto);
187         }
188 }
189
190
191 /******** E X T E R N ********/
192
193 PRIVATE ext_def()
194 {
195         if (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) {
196                 if (lib && !proto) {
197                         report("%L: %s %s also defined in %L",
198                                 dot, fun_or_var(dot), dot->id_name, lib);
199                 }
200                 if (proto) {
201                         chk_proto(dot);
202                 }
203                 ext = dot;
204                 dot = new_inpdef();
205                 get_dot();
206                 while (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) {
207                         report("%L: %s %s also defined at %L",
208                                 dot, fun_or_var(dot), dot->id_name, ext);
209                         get_dot();
210                 }
211         }
212 }
213
214 PRIVATE ext_decls()
215 {
216         while (same_obj(0) && dot->id_class == EFDC) {
217                 one_ext_decl("function", "variable", CL_VAR);
218         }
219
220         while (same_obj(0) && dot->id_class == EVDC) {
221                 one_ext_decl("variable", "function", CL_FUNC);
222         }
223
224         while (same_obj(0) && dot->id_class == IFDC) {
225                 one_ext_decl("function", "variable", CL_VAR);
226         }
227 }
228
229 PRIVATE one_ext_decl(kind, other_kind, other_class)
230         char *kind;
231         char *other_kind;
232         int other_class;
233 {
234         struct inpdef *def = (proto ? proto : ext ? ext : lib ? lib : 0);
235
236         if (!def) {
237                 /* the declaration will have to serve */
238                 ext = dot;
239                 dot = new_inpdef();
240                 get_dot();
241                 return;
242         }
243
244         if (is_class(def, other_class)) {
245                 /* e.g.: function FFF declared as variable at ... */
246                 report("%L: %s %s %s as %s at %L",
247                         dot, kind, dot->id_name,
248                         def_or_dec(def), other_kind, def
249                 );
250                 /* no further testing possible */
251                 get_dot();
252                 return;
253         }
254
255         if (!type_equal(dot->id_type, def->id_type)) {
256                 /* e.g.: type of variable VVV defined differently at ... */
257                 report("%L: type of %s %s %s differently at %L",
258                         dot, kind, dot->id_name, def_or_dec(def), def);
259
260                 /* no further testing needed */
261                 get_dot();
262                 return;
263         }
264
265         get_dot();
266 }
267
268
269 /******** U S A G E ********/
270
271 PRIVATE usage(stnr)
272         int stnr;
273 {
274         register struct inpdef *def =
275                 (stnr ? sta : proto ? proto : ext ? ext : lib ? lib : 0);
276         register int VU_count = 0;
277         register int VU_samefile = 0;
278
279         while (same_obj(stnr) && dot->id_class == FC) {
280                 one_func_call(def);
281         }
282
283         while (same_obj(stnr) && dot->id_class == VU) {
284                 VU_count++;
285                 if (def && streq(def->id_file, dot->id_file)) {
286                         VU_samefile++;
287                 }
288                 one_var_usage(def);
289         }
290
291         if (def && loptions['h']) {
292                 register char *fn = def->id_file;
293
294                 if (    stnr == 0
295                 &&      VU_count == 1
296                 &&      VU_samefile == 1
297                 &&      (       def == proto
298                         ||      (def == ext && !is_class(ext, CL_IMPL))
299                         )
300                 &&      streq(&fn[strlen(fn)-2], ".c")
301                 ) {
302                         report("%L: extern %s could be declared static",
303                                 def, def->id_name);
304                 }
305         }
306 }
307
308 PRIVATE one_func_call(def)
309         struct inpdef *def;
310 {
311         if (!def) {
312                 if (!loptions['u']) {
313                         report("%L: function %s used but not defined",
314                                 dot, dot->id_name);
315                 }
316                 get_dot();
317                 return;
318         }
319
320         def->id_called = 1;
321
322         if (def->id_args) {
323                 chk_args(dot, def);
324                 if (    dot->id_valused == USED
325                 &&      def->id_valreturned == NOVALRETURNED
326                 ) {
327                         report("%L: value of %s is used, but none is returned at %L",
328                                 dot, dot->id_name, def);
329                 }
330         }
331
332         switch (dot->id_valused) {
333         case USED:
334                 def->id_used = 1;
335                 break;
336         case IGNORED:
337                 def->id_ignored = 1;
338                 break;
339         case VOIDED:
340                 def->id_voided = 1;
341                 break;
342         default:
343                 panic("invalid dot->id_valused in one_func_call()");
344                 break;
345         }
346
347         get_dot();
348 }
349
350 PRIVATE one_var_usage(def)
351         struct inpdef *def;
352 {
353         if (!def) {
354                 if (!loptions['u']) {
355                         report("%L: variable %s used but not defined",
356                                 dot, dot->id_name);
357                 }
358                 get_dot();
359                 return;
360         }
361
362         def->id_called = 1;
363
364         get_dot();
365 }
366
367
368 /******** S T A T I C ********/
369
370 PRIVATE statics()
371 {
372         while (same_name()) {
373                 int stnr = dot->id_statnr;
374
375                 if (stnr == 0) {
376                         panic("sequence error in intermediate file: externals after statics");
377                 }
378
379                 if (sta) {
380                         free_inpdef(sta);
381                         sta = 0;
382                 }
383
384                 stat_def(stnr);
385                 usage(stnr);
386
387                 if (sta) {
388                         chk_def(sta);
389                 }
390
391                 if (same_obj(stnr)) {
392                         panic("sequence error in intermediate file: statics out of order");
393                 }
394         }
395 }
396
397 PRIVATE stat_def(stnr)
398         int stnr;
399 {
400         if (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) {
401                 if (lib) {
402                         report("%L: %s %s also defined in %L",
403                                 dot, fun_or_var(dot), dot->id_name, lib);
404                 }
405                 if (proto || ext) {
406                         struct inpdef *def = (proto ? proto : ext);
407
408                         if (!streq(dot->id_file, def->id_file)) {
409                                 report("%L: %s %s also %s at %L",
410                                         dot, fun_or_var(dot), dot->id_name,
411                                         def_or_dec(def), def
412                                 );
413                         }
414                 }
415                 sta = dot;
416                 dot = new_inpdef();
417                 get_dot();
418                 while (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) {
419                         report("%L: %s %s also defined at %L",
420                                 dot, fun_or_var(dot), dot->id_name, sta);
421                         get_dot();
422                 }
423         }
424 }
425
426 PRIVATE chk_def(def)
427         struct inpdef *def;
428 {
429         if (!def)
430                 return;
431
432         if (!def->id_called) {
433                 if (streq(def->id_name, "main")) {
434                         /* silent */
435                 }
436                 else if (ext && is_class(ext, CL_LIB)) {
437                         /* silent */
438                 }
439                 else {
440                         if (!loptions['u']) {
441                                 report("%L: %s %s not used anywhere",
442                                         def, fun_or_var(def), def->id_name);
443                         }
444                 }
445         }
446
447         if (is_class(def, CL_DEF|CL_FUNC)) {
448                 if (    def->id_valreturned == VALRETURNED
449                 &&      def->id_called
450                 &&      def->id_ignored
451                 ) {
452                         report("%L: %s returns value which is %s ignored",
453                                 def, def->id_name,
454                                 (def->id_used || def->id_voided) ?
455                                                 "sometimes" : "always");
456                 }
457         }
458 }
459
460
461 /******** D E B U G G I N G ********/
462
463 print_id(name, id)
464         char *name;
465         struct inpdef *id;
466 {
467         if (!id) {
468                 print("%s: <NO_INPDEF>\n", name);
469                 return;
470         }
471
472         print("%s: %s, %s, %04d, \"%s\", %d, %s", name,
473                 id->id_class == LFDF ? "LFDF" :
474                 id->id_class == LVDF ? "LVDF" :
475                 id->id_class == PFDF ? "PFDF" :
476                 id->id_class == EFDF ? "EFDF" :
477                 id->id_class == EVDF ? "EVDF" :
478                 id->id_class == EFDC ? "EFDC" :
479                 id->id_class == EVDC ? "EVDC" :
480                 id->id_class == IFDC ? "IFDC" :
481                 id->id_class == SFDF ? "SFDF" :
482                 id->id_class == SVDF ? "SVDF" :
483                 id->id_class == FC ? "FC" :
484                 id->id_class == VU ? "VU" : "<BADCLASS>",
485                 id->id_name,
486                 id->id_statnr,
487                 id->id_file,
488                 id->id_line,
489                 id->id_type
490         );
491         if (is_class(id, CL_FUNC|CL_DEF) || is_class(id, CL_FUNC|CL_USAGE)) {
492                 print(", %d, %s, %s",
493                         id->id_nrargs,
494                         (id->id_nrargs == 0 ? "" : id->id_argtps),
495                         (       id->id_class == FC
496                         ?       (       id->id_valused == USED ? "USED" :
497                                         id->id_valused == IGNORED ? "IGNORED" :
498                                         id->id_valused == VOIDED ? "VOIDED" :
499                                         "<BAD VALUSED>"
500                                 )
501                         :       (       id->id_valreturned == NOVALRETURNED
502                                 ?       "NOVALRETURNED"
503                                 :       id->id_valreturned == VALRETURNED
504                                 ?       "VALRETURNED"
505                                 :       id->id_valreturned == NORETURN
506                                 ?       "NORETURN"
507                                 :       "<BAD VALRETURNED>"
508                                 )
509                         )
510                 );
511         }
512         print("\n");
513 }
514