Oh GACK! src-clean doesn't quite work that easily since cleandist rebuilds the
[unix-history] / gnu / usr.bin / cc / cc1plus / cp-xref.c
CommitLineData
9bf86ebb
PR
1/* Code for handling XREF output from GNU C++.
2 Copyright (C) 1992, 1993 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann (tiemann@cygnus.com)
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING. If not, write to
19the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21
22#include "config.h"
23#include "tree.h"
24#include <stdio.h>
25#include "cp-tree.h"
26#include "input.h"
27
28#include <ctype.h>
29
30extern char *getpwd ();
31
32extern char *index ();
33extern char *rindex ();
34
35/* The character(s) used to join a directory specification (obtained with
36 getwd or equivalent) with a non-absolute file name. */
37
38#ifndef FILE_NAME_JOINER
39#define FILE_NAME_JOINER "/"
40#endif
41
42/* Nonzero if NAME as a file name is absolute. */
43#ifndef FILE_NAME_ABSOLUTE_P
44#define FILE_NAME_ABSOLUTE_P(NAME) (NAME[0] == '/')
45#endif
46
47/* For cross referencing. */
48
49int flag_gnu_xref;
50
51/************************************************************************/
52/* */
53/* Common definitions */
54/* */
55/************************************************************************/
56
57#ifndef TRUE
58#define TRUE 1
59#endif
60#ifndef FALSE
61#define FALSE 0
62#endif
63#ifndef NULL
64#define NULL 0
65#endif
66
67#define PALLOC(typ) ((typ *) calloc(1,sizeof(typ)))
68
69
70/* Return a malloc'd copy of STR. */
71#define SALLOC(str) \
72 ((char *) ((str) == NULL ? NULL \
73 : (char *) strcpy ((char *) malloc (strlen ((str)) + 1), (str))))
74#define SFREE(str) (str != NULL && (free(str),0))
75
76#define STREQL(s1,s2) (strcmp((s1),(s2)) == 0)
77#define STRNEQ(s1,s2) (strcmp((s1),(s2)) != 0)
78#define STRLSS(s1,s2) (strcmp((s1),(s2)) < 0)
79#define STRLEQ(s1,s2) (strcmp((s1),(s2)) <= 0)
80#define STRGTR(s1,s2) (strcmp((s1),(s2)) > 0)
81#define STRGEQ(s1,s2) (strcmp((s1),(s2)) >= 0)
82
83/************************************************************************/
84/* */
85/* Type definitions */
86/* */
87/************************************************************************/
88
89
90typedef struct _XREF_FILE * XREF_FILE;
91typedef struct _XREF_SCOPE * XREF_SCOPE;
92
93typedef struct _XREF_FILE
94{
95 char *name;
96 char *outname;
97 XREF_FILE next;
98} XREF_FILE_INFO;
99
100typedef struct _XREF_SCOPE
101{
102 int gid;
103 int lid;
104 XREF_FILE file;
105 int start;
106 XREF_SCOPE outer;
107} XREF_SCOPE_INFO;
108
109/************************************************************************/
110/* */
111/* Local storage */
112/* */
113/************************************************************************/
114
115static char doing_xref = 0;
116static FILE * xref_file = NULL;
117static char xref_name[1024];
118static XREF_FILE all_files = NULL;
119static char * wd_name = NULL;
120static XREF_SCOPE cur_scope = NULL;
121static int scope_ctr = 0;
122static XREF_FILE last_file = NULL;
123static tree last_fndecl = NULL;
124
125/************************************************************************/
126/* */
127/* Forward definitions */
128/* */
129/************************************************************************/
130
131extern void GNU_xref_begin();
132extern void GNU_xref_end();
133extern void GNU_xref_file();
134extern void GNU_xref_start_scope();
135extern void GNU_xref_end_scope();
136extern void GNU_xref_ref();
137extern void GNU_xref_decl();
138extern void GNU_xref_call();
139extern void GNU_xref_function();
140extern void GNU_xref_assign();
141extern void GNU_xref_hier();
142extern void GNU_xref_member();
143
144static void gen_assign();
145static XREF_FILE find_file();
146static char * filename();
147static char * fctname();
148static char * declname();
149static void simplify_type();
150static char * fixname();
151static void open_xref_file();
152
153extern char * type_as_string();
154
155/* Start cross referencing. FILE is the name of the file we xref. */
156
157void
158GNU_xref_begin (file)
159 char *file;
160{
161 doing_xref = 1;
162
163 if (file != NULL && STRNEQ (file,"-"))
164 {
165 open_xref_file(file);
166 GNU_xref_file(file);
167 }
168}
169
170/* Finish cross-referencing. ERRCNT is the number of errors
171 we encountered. */
172
173void
174GNU_xref_end (ect)
175 int ect;
176{
177 XREF_FILE xf;
178
179 if (!doing_xref) return;
180
181 xf = find_file (input_filename);
182 if (xf == NULL) return;
183
184 while (cur_scope != NULL)
185 GNU_xref_end_scope(cur_scope->gid,0,0,0,0);
186
187 doing_xref = 0;
188
189 if (xref_file == NULL) return;
190
191 fclose (xref_file);
192
193 xref_file = NULL;
194 all_files = NULL;
195
196 if (ect > 0) unlink (xref_name);
197}
198
199/* Write out xref for file named NAME. */
200
201void
202GNU_xref_file (name)
203 char *name;
204{
205 XREF_FILE xf;
206
207 if (!doing_xref || name == NULL) return;
208
209 if (xref_file == NULL)
210 {
211 open_xref_file (name);
212 if (!doing_xref) return;
213 }
214
215 if (all_files == NULL)
216 fprintf(xref_file,"SCP * 0 0 0 0 RESET\n");
217
218 xf = find_file (name);
219 if (xf != NULL) return;
220
221 xf = PALLOC (XREF_FILE_INFO);
222 xf->name = SALLOC (name);
223 xf->next = all_files;
224 all_files = xf;
225
226 if (wd_name == NULL)
227 wd_name = getpwd ();
228
229 if (FILE_NAME_ABSOLUTE_P (name) || ! wd_name)
230 xf->outname = xf->name;
231 else
232 {
233 char *nmbuf
234 = (char *) malloc (strlen (wd_name) + strlen (FILE_NAME_JOINER)
235 + strlen (name) + 1);
236 sprintf (nmbuf, "%s%s%s", wd_name, FILE_NAME_JOINER, name);
237 name = nmbuf;
238 xf->outname = nmbuf;
239 }
240
241 fprintf (xref_file, "FIL %s %s 0\n", name, wd_name);
242
243 filename (xf);
244 fctname (NULL);
245}
246
247/* Start a scope identified at level ID. */
248
249void
250GNU_xref_start_scope (id)
251 HOST_WIDE_INT id;
252{
253 XREF_SCOPE xs;
254 XREF_FILE xf;
255
256 if (!doing_xref) return;
257 xf = find_file (input_filename);
258
259 xs = PALLOC (XREF_SCOPE_INFO);
260 xs->file = xf;
261 xs->start = lineno;
262 if (xs->start <= 0) xs->start = 1;
263 xs->gid = id;
264 xs->lid = ++scope_ctr;
265 xs->outer = cur_scope;
266 cur_scope = xs;
267}
268
269/* Finish a scope at level ID.
270 INID is ???
271 PRM is ???
272 KEEP is nonzero iff this scope is retained (nonzero if it's
273 a compiler-generated invisible scope).
274 TRNS is ??? */
275
276void
277GNU_xref_end_scope (id,inid,prm,keep,trns)
278 HOST_WIDE_INT id;
279 HOST_WIDE_INT inid;
280 int prm,keep,trns;
281{
282 XREF_FILE xf;
283 XREF_SCOPE xs,lxs,oxs;
284 char *stype;
285
286 if (!doing_xref) return;
287 xf = find_file (input_filename);
288 if (xf == NULL) return;
289
290 lxs = NULL;
291 for (xs = cur_scope; xs != NULL; xs = xs->outer)
292 {
293 if (xs->gid == id) break;
294 lxs = xs;
295 }
296 if (xs == NULL) return;
297
298 if (inid != 0) {
299 for (oxs = cur_scope; oxs != NULL; oxs = oxs->outer) {
300 if (oxs->gid == inid) break;
301 }
302 if (oxs == NULL) return;
303 inid = oxs->lid;
304 }
305
306 if (prm == 2) stype = "SUE";
307 else if (prm != 0) stype = "ARGS";
308 else if (keep == 2 || inid != 0) stype = "INTERN";
309 else stype = "EXTERN";
310
311 fprintf (xref_file,"SCP %s %d %d %d %d %s\n",
312 filename (xf), xs->start, lineno,xs->lid, inid, stype);
313
314 if (lxs == NULL) cur_scope = xs->outer;
315 else lxs->outer = xs->outer;
316
317 free (xs);
318}
319
320/* Output a reference to NAME in FNDECL. */
321
322void
323GNU_xref_ref (fndecl,name)
324 tree fndecl;
325 char *name;
326{
327 XREF_FILE xf;
328
329 if (!doing_xref) return;
330 xf = find_file (input_filename);
331 if (xf == NULL) return;
332
333 fprintf (xref_file, "REF %s %d %s %s\n",
334 filename (xf), lineno, fctname (fndecl), name);
335}
336
337/* Output a reference to DECL in FNDECL. */
338
339void
340GNU_xref_decl (fndecl,decl)
341 tree fndecl;
342 tree decl;
343{
344 XREF_FILE xf,xf1;
345 char *cls;
346 char *name;
347 char buf[10240];
348 int uselin;
349
350 if (!doing_xref) return;
351 xf = find_file (input_filename);
352 if (xf == NULL) return;
353
354 uselin = FALSE;
355
356 if (TREE_CODE (decl) == TYPE_DECL) cls = "TYPEDEF";
357 else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
358 else if (TREE_CODE (decl) == VAR_DECL)
359 {
360 if (fndecl == NULL && TREE_STATIC(decl)
361 && TREE_READONLY(decl) && DECL_INITIAL(decl) != 0
362 && !TREE_PUBLIC(decl) && !DECL_EXTERNAL(decl)
363 && DECL_MODE(decl) != BLKmode) cls = "CONST";
364 else if (DECL_EXTERNAL(decl)) cls = "EXTERN";
365 else if (TREE_PUBLIC(decl)) cls = "EXTDEF";
366 else if (TREE_STATIC(decl)) cls = "STATIC";
367 else if (DECL_REGISTER(decl)) cls = "REGISTER";
368 else cls = "AUTO";
369 }
370 else if (TREE_CODE (decl) == PARM_DECL) cls = "PARAM";
371 else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
372 else if (TREE_CODE (decl) == CONST_DECL) cls = "CONST";
373 else if (TREE_CODE (decl) == FUNCTION_DECL)
374 {
375 if (DECL_EXTERNAL (decl)) cls = "EXTERN";
376 else if (TREE_PUBLIC (decl)) cls = "EFUNCTION";
377 else cls = "SFUNCTION";
378 }
379 else if (TREE_CODE (decl) == LABEL_DECL) cls = "LABEL";
380 else if (TREE_CODE (decl) == UNION_TYPE)
381 {
382 cls = "UNIONID";
383 decl = TYPE_NAME (decl);
384 uselin = TRUE;
385 }
386 else if (TREE_CODE (decl) == RECORD_TYPE)
387 {
388 if (CLASSTYPE_DECLARED_CLASS (decl)) cls = "CLASSID";
389 else cls = "STRUCTID";
390 decl = TYPE_NAME (decl);
391 uselin = TRUE;
392 }
393 else if (TREE_CODE (decl) == ENUMERAL_TYPE)
394 {
395 cls = "ENUMID";
396 decl = TYPE_NAME (decl);
397 uselin = TRUE;
398 }
399 else cls = "UNKNOWN";
400
401 if (decl == NULL || DECL_NAME (decl) == NULL) return;
402
403 if (uselin && decl->decl.linenum > 0 && decl->decl.filename != NULL)
404 {
405 xf1 = find_file (decl->decl.filename);
406 if (xf1 != NULL)
407 {
408 lineno = decl->decl.linenum;
409 xf = xf1;
410 }
411 }
412
413 if (DECL_ASSEMBLER_NAME (decl))
414 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
415 else
416 name = IDENTIFIER_POINTER (DECL_NAME (decl));
417
418 strcpy (buf, type_as_string (TREE_TYPE (decl)));
419 simplify_type (buf);
420
421 fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
422 filename(xf), lineno, name,
423 (cur_scope != NULL ? cur_scope->lid : 0),
424 cls, fctname(fndecl), buf);
425
426 if (STREQL (cls, "STRUCTID") || STREQL (cls, "UNIONID"))
427 {
428 cls = "CLASSID";
429 fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
430 filename(xf), lineno,name,
431 (cur_scope != NULL ? cur_scope->lid : 0),
432 cls, fctname(fndecl), buf);
433 }
434}
435
436/* Output a reference to a call to NAME in FNDECL. */
437
438void
439GNU_xref_call (fndecl, name)
440 tree fndecl;
441 char *name;
442{
443 XREF_FILE xf;
444 char buf[1024];
445 char *s;
446
447 if (!doing_xref) return;
448 xf = find_file (input_filename);
449 if (xf == NULL) return;
450 name = fixname (name, buf);
451
452 for (s = name; *s != 0; ++s)
453 if (*s == '_' && s[1] == '_') break;
454 if (*s != 0) GNU_xref_ref (fndecl, name);
455
456 fprintf (xref_file, "CAL %s %d %s %s\n",
457 filename (xf), lineno, name, fctname (fndecl));
458}
459
460/* Output cross-reference info about FNDECL. If non-NULL,
461 ARGS are the arguments for the function (i.e., before the FUNCTION_DECL
462 has been fully built). */
463
464void
465GNU_xref_function (fndecl, args)
466 tree fndecl;
467 tree args;
468{
469 XREF_FILE xf;
470 int ct;
471 char buf[1024];
472
473 if (!doing_xref) return;
474 xf = find_file (input_filename);
475 if (xf == NULL) return;
476
477 ct = 0;
478 buf[0] = 0;
479 if (args == NULL) args = DECL_ARGUMENTS (fndecl);
480
481 GNU_xref_decl (NULL, fndecl);
482
483 for ( ; args != NULL; args = TREE_CHAIN (args))
484 {
485 GNU_xref_decl (fndecl,args);
486 if (ct != 0) strcat (buf,",");
487 strcat (buf, declname (args));
488 ++ct;
489 }
490
491 fprintf (xref_file, "PRC %s %d %s %d %d %s\n",
492 filename(xf), lineno, declname(fndecl),
493 (cur_scope != NULL ? cur_scope->lid : 0),
494 ct, buf);
495}
496
497/* Output cross-reference info about an assignment to NAME. */
498
499void
500GNU_xref_assign(name)
501 tree name;
502{
503 XREF_FILE xf;
504
505 if (!doing_xref) return;
506 xf = find_file(input_filename);
507 if (xf == NULL) return;
508
509 gen_assign(xf, name);
510}
511
512static void
513gen_assign(xf, name)
514 XREF_FILE xf;
515 tree name;
516{
517 char *s;
518
519 s = NULL;
520
521 switch (TREE_CODE (name))
522 {
523 case IDENTIFIER_NODE :
524 s = IDENTIFIER_POINTER(name);
525 break;
526 case VAR_DECL :
527 s = declname(name);
528 break;
529 case COMPONENT_REF :
530 gen_assign(xf, TREE_OPERAND(name, 0));
531 gen_assign(xf, TREE_OPERAND(name, 1));
532 break;
533 case INDIRECT_REF :
534 case OFFSET_REF :
535 case ARRAY_REF :
536 case BUFFER_REF :
537 gen_assign(xf, TREE_OPERAND(name, 0));
538 break;
539 case COMPOUND_EXPR :
540 gen_assign(xf, TREE_OPERAND(name, 1));
541 break;
542 default :
543 break;
544 }
545
546 if (s != NULL)
547 fprintf(xref_file, "ASG %s %d %s\n", filename(xf), lineno, s);
548}
549
550/* Output cross-reference info about a class hierarchy.
551 CLS is the class type of interest. BASE is a baseclass
552 for CLS. PUB and VIRT give the visibility info about
553 the class derivation. FRND is nonzero iff BASE is a friend
554 of CLS.
555
556 ??? Needs to handle nested classes. */
557void
558GNU_xref_hier(cls, base, pub, virt, frnd)
559 char *cls;
560 char *base;
561 int pub;
562 int virt;
563 int frnd;
564{
565 XREF_FILE xf;
566
567 if (!doing_xref) return;
568 xf = find_file(input_filename);
569 if (xf == NULL) return;
570
571 fprintf(xref_file, "HIE %s %d %s %s %d %d %d\n",
572 filename(xf), lineno, cls, base, pub, virt, frnd);
573}
574
575/* Output cross-reference info about class members. CLS
576 is the containing type; FLD is the class member. */
577
578void
579GNU_xref_member(cls, fld)
580 tree cls;
581 tree fld;
582{
583 XREF_FILE xf;
584 char *prot;
585 int confg, pure;
586 char *d;
587 int i;
588 char buf[1024], bufa[1024];
589
590 if (!doing_xref) return;
591 xf = find_file(fld->decl.filename);
592 if (xf == NULL) return;
593
594 if (TREE_PRIVATE (fld)) prot = "PRIVATE";
595 else if (TREE_PROTECTED(fld)) prot = "PROTECTED";
596 else prot = "PUBLIC";
597
598 confg = 0;
599 if (TREE_CODE (fld) == FUNCTION_DECL && DECL_CONST_MEMFUNC_P(fld))
600 confg = 1;
601 else if (TREE_CODE (fld) == CONST_DECL)
602 confg = 1;
603
604 pure = 0;
605 if (TREE_CODE (fld) == FUNCTION_DECL && DECL_ABSTRACT_VIRTUAL_P(fld))
606 pure = 1;
607
608 d = IDENTIFIER_POINTER(cls);
609 sprintf(buf, "%d%s", strlen(d), d);
610 i = strlen(buf);
611 strcpy(bufa, declname(fld));
612
613#ifdef XREF_SHORT_MEMBER_NAMES
614 for (p = &bufa[1]; *p != 0; ++p)
615 {
616 if (p[0] == '_' && p[1] == '_' && p[2] >= '0' && p[2] <= '9') {
617 if (strncmp(&p[2], buf, i) == 0) *p = 0;
618 break;
619 }
620 else if (p[0] == '_' && p[1] == '_' && p[2] == 'C' && p[3] >= '0' && p[3] <= '9') {
621 if (strncmp(&p[3], buf, i) == 0) *p = 0;
622 break;
623 }
624 }
625#endif
626
627 fprintf(xref_file, "MEM %s %d %s %s %s %d %d %d %d %d %d %d\n",
628 filename(xf), fld->decl.linenum, d, bufa, prot,
629 (TREE_CODE (fld) == FUNCTION_DECL ? 0 : 1),
630 (DECL_INLINE (fld) ? 1 : 0),
631 (DECL_FRIEND_P(fld) ? 1 : 0),
632 (DECL_VINDEX(fld) ? 1 : 0),
633 (TREE_STATIC(fld) ? 1 : 0),
634 pure, confg);
635}
636
637/* Find file entry given name. */
638
639static XREF_FILE
640find_file(name)
641 char *name;
642{
643 XREF_FILE xf;
644
645 for (xf = all_files; xf != NULL; xf = xf->next) {
646 if (STREQL(name, xf->name)) break;
647 }
648
649 return xf;
650}
651
652/* Return filename for output purposes. */
653
654static char *
655filename(xf)
656 XREF_FILE xf;
657{
658 if (xf == NULL) {
659 last_file = NULL;
660 return "*";
661 }
662
663 if (last_file == xf) return "*";
664
665 last_file = xf;
666
667 return xf->outname;
668}
669
670/* Return function name for output purposes. */
671
672static char *
673fctname(fndecl)
674 tree fndecl;
675{
676 static char fctbuf[1024];
677 char *s;
678
679 if (fndecl == NULL && last_fndecl == NULL) return "*";
680
681 if (fndecl == NULL)
682 {
683 last_fndecl = NULL;
684 return "*TOP*";
685 }
686
687 if (fndecl == last_fndecl) return "*";
688
689 last_fndecl = fndecl;
690
691 s = declname(fndecl);
692 s = fixname(s, fctbuf);
693
694 return s;
695}
696
697/* Return decl name for output purposes. */
698
699static char *
700declname(dcl)
701 tree dcl;
702{
703 if (DECL_NAME (dcl) == NULL) return "?";
704
705 if (DECL_ASSEMBLER_NAME (dcl))
706 return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (dcl));
707 else
708 return IDENTIFIER_POINTER (DECL_NAME (dcl));
709}
710
711/* Simplify a type string by removing unneeded parenthesis. */
712
713static void
714simplify_type(typ)
715 char *typ;
716{
717 char *s;
718 int lvl, i;
719
720 i = strlen(typ);
721 while (i > 0 && isspace(typ[i-1])) typ[--i] = 0;
722
723 if (i > 7 && STREQL(&typ[i-5], "const"))
724 {
725 typ[i-5] = 0;
726 i -= 5;
727 }
728
729 if (typ[i-1] != ')') return;
730
731 s = &typ[i-2];
732 lvl = 1;
733 while (*s != 0) {
734 if (*s == ')') ++lvl;
735 else if (*s == '(')
736 {
737 --lvl;
738 if (lvl == 0)
739 {
740 s[1] = ')';
741 s[2] = 0;
742 break;
743 }
744 }
745 --s;
746 }
747
748 if (*s != 0 && s[-1] == ')')
749 {
750 --s;
751 --s;
752 if (*s == '(') s[2] = 0;
753 else if (*s == ':') {
754 while (*s != '(') --s;
755 s[1] = ')';
756 s[2] = 0;
757 }
758 }
759}
760
761/* Fixup a function name (take care of embedded spaces). */
762
763static char *
764fixname(nam, buf)
765 char *nam;
766 char *buf;
767{
768 char *s, *t;
769 int fg;
770
771 s = nam;
772 t = buf;
773 fg = 0;
774
775 while (*s != 0)
776 {
777 if (*s == ' ')
778 {
779 *t++ = '\36';
780 ++fg;
781 }
782 else *t++ = *s;
783 ++s;
784 }
785 *t = 0;
786
787 if (fg == 0) return nam;
788
789 return buf;
790}
791
792/* Open file for xrefing. */
793
794static void
795open_xref_file(file)
796 char *file;
797{
798 char *s, *t;
799
800#ifdef XREF_FILE_NAME
801 XREF_FILE_NAME (xref_name, file);
802#else
803 s = rindex (file, '/');
804 if (s == NULL)
805 sprintf (xref_name, ".%s.gxref", file);
806 else
807 {
808 ++s;
809 strcpy (xref_name, file);
810 t = rindex (xref_name, '/');
811 ++t;
812 *t++ = '.';
813 strcpy (t, s);
814 strcat (t, ".gxref");
815 }
816#endif /* no XREF_FILE_NAME */
817
818 xref_file = fopen(xref_name, "w");
819
820 if (xref_file == NULL)
821 {
822 error("Can't create cross-reference file `%s'", xref_name);
823 doing_xref = 0;
824 }
825}