]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/xr_tabls.adb
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / ada / xr_tabls.adb
CommitLineData
415dddc8
RK
1------------------------------------------------------------------------------
2-- --
3-- GNAT COMPILER COMPONENTS --
4-- --
5-- X R _ T A B L S --
6-- --
7-- B o d y --
8-- --
8d0d46f4 9-- Copyright (C) 1998-2021, Free Software Foundation, Inc. --
415dddc8
RK
10-- --
11-- GNAT is free software; you can redistribute it and/or modify it under --
12-- terms of the GNU General Public License as published by the Free Soft- --
b5c84c3c 13-- ware Foundation; either version 3, or (at your option) any later ver- --
415dddc8
RK
14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17-- for more details. You should have received a copy of the GNU General --
b5c84c3c
RD
18-- Public License distributed with GNAT; see file COPYING3. If not, go to --
19-- http://www.gnu.org/licenses for a complete copy of the license. --
415dddc8 20-- --
fbf5a39b
AC
21-- GNAT was originally developed by the GNAT team at New York University. --
22-- Extensive contributions were provided by Ada Core Technologies Inc. --
415dddc8
RK
23-- --
24------------------------------------------------------------------------------
25
fbf5a39b 26with Types; use Types;
07fc65c4 27with Osint;
07fc65c4 28
fbf5a39b
AC
29with Ada.Unchecked_Conversion;
30with Ada.Unchecked_Deallocation;
415dddc8
RK
31with Ada.Strings.Fixed;
32with Ada.Strings;
33with Ada.Text_IO;
fbf5a39b
AC
34with Ada.Characters.Handling; use Ada.Characters.Handling;
35with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
07fc65c4 36
415dddc8
RK
37with GNAT.OS_Lib; use GNAT.OS_Lib;
38with GNAT.Directory_Operations; use GNAT.Directory_Operations;
851e9f19 39with GNAT.HTable;
fbf5a39b 40with GNAT.Heap_Sort_G;
415dddc8
RK
41
42package body Xr_Tabls is
43
fbf5a39b
AC
44 type HTable_Headers is range 1 .. 10000;
45
46 procedure Set_Next (E : File_Reference; Next : File_Reference);
47 function Next (E : File_Reference) return File_Reference;
48 function Get_Key (E : File_Reference) return Cst_String_Access;
49 function Hash (F : Cst_String_Access) return HTable_Headers;
50 function Equal (F1, F2 : Cst_String_Access) return Boolean;
3354f96d 51 -- The five subprograms above are used to instantiate the static
fbf5a39b
AC
52 -- htable to store the files that should be processed.
53
54 package File_HTable is new GNAT.HTable.Static_HTable
55 (Header_Num => HTable_Headers,
56 Element => File_Record,
57 Elmt_Ptr => File_Reference,
58 Null_Ptr => null,
59 Set_Next => Set_Next,
60 Next => Next,
61 Key => Cst_String_Access,
62 Get_Key => Get_Key,
63 Hash => Hash,
64 Equal => Equal);
65 -- A hash table to store all the files referenced in the
66 -- application. The keys in this htable are the name of the files
67 -- themselves, therefore it is assumed that the source path
68 -- doesn't contain twice the same source or ALI file name
69
70 type Unvisited_Files_Record;
71 type Unvisited_Files_Access is access Unvisited_Files_Record;
72 type Unvisited_Files_Record is record
73 File : File_Reference;
74 Next : Unvisited_Files_Access;
75 end record;
76 -- A special list, in addition to File_HTable, that only stores
77 -- the files that haven't been visited so far. Note that the File
78 -- list points to some data in File_HTable, and thus should never be freed.
79
80 function Next (E : Declaration_Reference) return Declaration_Reference;
81 procedure Set_Next (E, Next : Declaration_Reference);
82 function Get_Key (E : Declaration_Reference) return Cst_String_Access;
3354f96d 83 -- The subprograms above are used to instantiate the static
fbf5a39b
AC
84 -- htable to store the entities that have been found in the application
85
86 package Entities_HTable is new GNAT.HTable.Static_HTable
87 (Header_Num => HTable_Headers,
88 Element => Declaration_Record,
89 Elmt_Ptr => Declaration_Reference,
90 Null_Ptr => null,
91 Set_Next => Set_Next,
92 Next => Next,
93 Key => Cst_String_Access,
94 Get_Key => Get_Key,
95 Hash => Hash,
96 Equal => Equal);
97 -- A hash table to store all the entities defined in the
98 -- application. For each entity, we store a list of its reference
99 -- locations as well.
100 -- The keys in this htable should be created with Key_From_Ref,
101 -- and are the file, line and column of the declaration, which are
102 -- unique for every entity.
103
104 Entities_Count : Natural := 0;
105 -- Number of entities in Entities_HTable. This is used in the end
106 -- when sorting the table.
107
108 Longest_File_Name_In_Table : Natural := 0;
2d5e5d89
AC
109 -- The length of the longest file name stored
110
111 Unvisited_Files : Unvisited_Files_Access := null;
112 -- Linked list of unvisited files
113
114 Directories : Project_File_Ptr;
115 -- Store the list of directories to visit
116
117 Default_Match : Boolean := False;
118 -- Default value for match in declarations
fbf5a39b
AC
119
120 function Parse_Gnatls_Src return String;
121 -- Return the standard source directories (taking into account the
122 -- ADA_INCLUDE_PATH environment variable, if Osint.Add_Default_Search_Dirs
123 -- was called first).
124
125 function Parse_Gnatls_Obj return String;
126 -- Return the standard object directories (taking into account the
127 -- ADA_OBJECTS_PATH environment variable).
128
129 function Key_From_Ref
130 (File_Ref : File_Reference;
131 Line : Natural;
132 Column : Natural)
133 return String;
134 -- Return a key for the symbol declared at File_Ref, Line,
135 -- Column. This key should be used for lookup in Entity_HTable
136
137 function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean;
9de61fcb 138 -- Compare two declarations (the comparison is case-insensitive)
fbf5a39b
AC
139
140 function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean;
141 -- Compare two references
142
143 procedure Store_References
144 (Decl : Declaration_Reference;
145 Get_Writes : Boolean := False;
146 Get_Reads : Boolean := False;
147 Get_Bodies : Boolean := False;
148 Get_Declaration : Boolean := False;
149 Arr : in out Reference_Array;
150 Index : in out Natural);
9de61fcb
RD
151 -- Store in Arr, starting at Index, all the references to Decl. The Get_*
152 -- parameters can be used to indicate which references should be stored.
fbf5a39b
AC
153 -- Constraint_Error will be raised if Arr is not big enough.
154
155 procedure Sort (Arr : in out Reference_Array);
9de61fcb 156 -- Sort an array of references (Arr'First must be 1)
fbf5a39b
AC
157
158 --------------
159 -- Set_Next --
160 --------------
161
162 procedure Set_Next (E : File_Reference; Next : File_Reference) is
163 begin
164 E.Next := Next;
165 end Set_Next;
166
167 procedure Set_Next
168 (E : Declaration_Reference; Next : Declaration_Reference) is
169 begin
170 E.Next := Next;
171 end Set_Next;
172
173 -------------
174 -- Get_Key --
175 -------------
176
177 function Get_Key (E : File_Reference) return Cst_String_Access is
178 begin
179 return E.File;
180 end Get_Key;
415dddc8 181
fbf5a39b
AC
182 function Get_Key (E : Declaration_Reference) return Cst_String_Access is
183 begin
184 return E.Key;
185 end Get_Key;
186
187 ----------
188 -- Hash --
189 ----------
190
191 function Hash (F : Cst_String_Access) return HTable_Headers is
192 function H is new GNAT.HTable.Hash (HTable_Headers);
193
194 begin
195 return H (F.all);
196 end Hash;
415dddc8 197
fbf5a39b
AC
198 -----------
199 -- Equal --
200 -----------
415dddc8 201
fbf5a39b
AC
202 function Equal (F1, F2 : Cst_String_Access) return Boolean is
203 begin
204 return F1.all = F2.all;
205 end Equal;
206
207 ------------------
208 -- Key_From_Ref --
209 ------------------
210
211 function Key_From_Ref
212 (File_Ref : File_Reference;
213 Line : Natural;
214 Column : Natural)
215 return String
216 is
217 begin
218 return File_Ref.File.all & Natural'Image (Line) & Natural'Image (Column);
219 end Key_From_Ref;
415dddc8
RK
220
221 ---------------------
222 -- Add_Declaration --
223 ---------------------
224
225 function Add_Declaration
fbf5a39b
AC
226 (File_Ref : File_Reference;
227 Symbol : String;
228 Line : Natural;
229 Column : Natural;
230 Decl_Type : Character;
54f471f0 231 Is_Parameter : Boolean := False;
fbf5a39b
AC
232 Remove_Only : Boolean := False;
233 Symbol_Match : Boolean := True)
234 return Declaration_Reference
415dddc8 235 is
fbf5a39b
AC
236 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
237 (Declaration_Record, Declaration_Reference);
415dddc8 238
fbf5a39b 239 Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column);
415dddc8 240
fbf5a39b
AC
241 New_Decl : Declaration_Reference :=
242 Entities_HTable.Get (Key'Unchecked_Access);
415dddc8 243
54f471f0 244 Is_Param : Boolean := Is_Parameter;
415dddc8 245
fbf5a39b
AC
246 begin
247 -- Insert the Declaration in the table. There might already be a
248 -- declaration in the table if the entity is a parameter, so we
249 -- need to check that first.
250
251 if New_Decl /= null and then New_Decl.Symbol_Length = 0 then
54f471f0 252 Is_Param := Is_Parameter or else New_Decl.Is_Parameter;
fbf5a39b
AC
253 Entities_HTable.Remove (Key'Unrestricted_Access);
254 Entities_Count := Entities_Count - 1;
255 Free (New_Decl.Key);
256 Unchecked_Free (New_Decl);
257 New_Decl := null;
415dddc8
RK
258 end if;
259
fbf5a39b
AC
260 -- The declaration might also already be there for parent types. In
261 -- this case, we should keep the entry, since some other entries are
262 -- pointing to it.
263
264 if New_Decl = null
265 and then not Remove_Only
266 then
267 New_Decl :=
268 new Declaration_Record'
269 (Symbol_Length => Symbol'Length,
270 Symbol => Symbol,
271 Key => new String'(Key),
272 Decl => new Reference_Record'
273 (File => File_Ref,
274 Line => Line,
275 Column => Column,
276 Source_Line => null,
277 Next => null),
54f471f0 278 Is_Parameter => Is_Param,
fbf5a39b
AC
279 Decl_Type => Decl_Type,
280 Body_Ref => null,
281 Ref_Ref => null,
282 Modif_Ref => null,
283 Match => Symbol_Match
284 and then
285 (Default_Match
286 or else Match (File_Ref, Line, Column)),
287 Par_Symbol => null,
288 Next => null);
289
290 Entities_HTable.Set (New_Decl);
291 Entities_Count := Entities_Count + 1;
292
293 if New_Decl.Match then
294 Longest_File_Name_In_Table :=
295 Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
296 end if;
297
298 elsif New_Decl /= null
299 and then not New_Decl.Match
300 then
301 New_Decl.Match := Default_Match
302 or else Match (File_Ref, Line, Column);
a5a809b2 303 New_Decl.Is_Parameter := New_Decl.Is_Parameter or Is_Param;
54f471f0
AC
304
305 elsif New_Decl /= null then
a5a809b2 306 New_Decl.Is_Parameter := New_Decl.Is_Parameter or Is_Param;
415dddc8
RK
307 end if;
308
309 return New_Decl;
310 end Add_Declaration;
311
07fc65c4
GB
312 ----------------------
313 -- Add_To_Xref_File --
314 ----------------------
415dddc8 315
fbf5a39b 316 function Add_To_Xref_File
07fc65c4 317 (File_Name : String;
07fc65c4
GB
318 Visited : Boolean := True;
319 Emit_Warning : Boolean := False;
320 Gnatchop_File : String := "";
fbf5a39b 321 Gnatchop_Offset : Integer := 0) return File_Reference
415dddc8 322 is
fbf5a39b
AC
323 Base : aliased constant String := Base_Name (File_Name);
324 Dir : constant String := Dir_Name (File_Name);
325 Dir_Acc : GNAT.OS_Lib.String_Access := null;
326 Ref : File_Reference;
415dddc8
RK
327
328 begin
07fc65c4
GB
329 -- Do we have a directory name as well?
330
fbf5a39b
AC
331 if File_Name /= Base then
332 Dir_Acc := new String'(Dir);
415dddc8
RK
333 end if;
334
fbf5a39b
AC
335 Ref := File_HTable.Get (Base'Unchecked_Access);
336 if Ref = null then
337 Ref := new File_Record'
338 (File => new String'(Base),
339 Dir => Dir_Acc,
340 Lines => null,
341 Visited => Visited,
342 Emit_Warning => Emit_Warning,
343 Gnatchop_File => new String'(Gnatchop_File),
344 Gnatchop_Offset => Gnatchop_Offset,
345 Next => null);
346 File_HTable.Set (Ref);
415dddc8 347
fbf5a39b 348 if not Visited then
415dddc8 349
fbf5a39b 350 -- Keep a separate list for faster access
415dddc8 351
fbf5a39b
AC
352 Set_Unvisited (Ref);
353 end if;
354 end if;
355 return Ref;
07fc65c4 356 end Add_To_Xref_File;
415dddc8
RK
357
358 --------------
359 -- Add_Line --
360 --------------
361
362 procedure Add_Line
363 (File : File_Reference;
364 Line : Natural;
365 Column : Natural)
366 is
367 begin
368 File.Lines := new Ref_In_File'(Line => Line,
369 Column => Column,
370 Next => File.Lines);
371 end Add_Line;
372
373 ----------------
374 -- Add_Parent --
375 ----------------
376
377 procedure Add_Parent
378 (Declaration : in out Declaration_Reference;
379 Symbol : String;
380 Line : Natural;
381 Column : Natural;
382 File_Ref : File_Reference)
383 is
384 begin
fbf5a39b
AC
385 Declaration.Par_Symbol :=
386 Add_Declaration
387 (File_Ref, Symbol, Line, Column,
388 Decl_Type => ' ',
389 Symbol_Match => False);
415dddc8
RK
390 end Add_Parent;
391
392 -------------------
393 -- Add_Reference --
394 -------------------
395
396 procedure Add_Reference
fbf5a39b
AC
397 (Declaration : Declaration_Reference;
398 File_Ref : File_Reference;
399 Line : Natural;
400 Column : Natural;
401 Ref_Type : Character;
402 Labels_As_Ref : Boolean)
415dddc8 403 is
fbf5a39b 404 New_Ref : Reference;
54f471f0
AC
405 New_Decl : Declaration_Reference;
406 pragma Unreferenced (New_Decl);
415dddc8
RK
407
408 begin
409 case Ref_Type is
d8f43ee6
HK
410 when ' ' | 'b' | 'c' | 'H' | 'i' | 'm' | 'o' | 'r' | 'R' | 's' | 'x'
411 =>
fbf5a39b 412 null;
07fc65c4 413
fbf5a39b
AC
414 when 'l' | 'w' =>
415 if not Labels_As_Ref then
416 return;
417 end if;
07fc65c4 418
fbf5a39b 419 when '=' | '<' | '>' | '^' =>
07fc65c4 420
a5a809b2
AC
421 -- Create dummy declaration in table to report it as a parameter
422
54f471f0
AC
423 -- In a given ALI file, the declaration of the subprogram comes
424 -- before the declaration of the parameter. However, it is
425 -- possible that another ALI file has been parsed that also
a5a809b2
AC
426 -- references the parameter (for instance a named parameter in
427 -- a call), so we need to check whether there already exists a
54f471f0
AC
428 -- declaration for the parameter.
429
a5a809b2
AC
430 New_Decl :=
431 Add_Declaration
432 (File_Ref => File_Ref,
433 Symbol => "",
434 Line => Line,
435 Column => Column,
436 Decl_Type => ' ',
437 Is_Parameter => True);
fbf5a39b 438
d8f43ee6 439 when 'd' | 'e' | 'E' | 'k' | 'p' | 'P' | 't' | 'z' =>
07fc65c4
GB
440 return;
441
d8f43ee6 442 when others =>
07fc65c4
GB
443 Ada.Text_IO.Put_Line ("Unknown reference type: " & Ref_Type);
444 return;
415dddc8
RK
445 end case;
446
fbf5a39b
AC
447 New_Ref := new Reference_Record'
448 (File => File_Ref,
449 Line => Line,
450 Column => Column,
451 Source_Line => null,
452 Next => null);
415dddc8 453
cead616d
AC
454 -- We can insert the reference into the list directly, since all the
455 -- references will appear only once in the ALI file corresponding to the
456 -- file where they are referenced. This saves a lot of time compared to
457 -- checking the list to check if it exists.
415dddc8 458
fbf5a39b
AC
459 case Ref_Type is
460 when 'b' | 'c' =>
461 New_Ref.Next := Declaration.Body_Ref;
462 Declaration.Body_Ref := New_Ref;
415dddc8 463
d8f43ee6 464 when ' ' | 'H' | 'i' | 'l' | 'o' | 'r' | 'R' | 's' | 'w' | 'x' =>
fbf5a39b
AC
465 New_Ref.Next := Declaration.Ref_Ref;
466 Declaration.Ref_Ref := New_Ref;
415dddc8 467
fbf5a39b
AC
468 when 'm' =>
469 New_Ref.Next := Declaration.Modif_Ref;
470 Declaration.Modif_Ref := New_Ref;
415dddc8 471
fbf5a39b
AC
472 when others =>
473 null;
474 end case;
415dddc8
RK
475
476 if not Declaration.Match then
477 Declaration.Match := Match (File_Ref, Line, Column);
478 end if;
479
480 if Declaration.Match then
fbf5a39b
AC
481 Longest_File_Name_In_Table :=
482 Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
415dddc8
RK
483 end if;
484 end Add_Reference;
485
486 -------------------
487 -- ALI_File_Name --
488 -------------------
489
490 function ALI_File_Name (Ada_File_Name : String) return String is
2d5e5d89
AC
491 -- Should ideally be based on the naming scheme defined in
492 -- project files but this is too late for an obsolescent feature.
fbf5a39b
AC
493
494 Index : constant Natural :=
495 Ada.Strings.Fixed.Index
496 (Ada_File_Name, ".", Going => Ada.Strings.Backward);
415dddc8
RK
497
498 begin
499 if Index /= 0 then
0e47ff5c
AC
500 return Ada_File_Name (Ada_File_Name'First .. Index)
501 & Osint.ALI_Suffix.all;
415dddc8 502 else
0e47ff5c 503 return Ada_File_Name & "." & Osint.ALI_Suffix.all;
415dddc8
RK
504 end if;
505 end ALI_File_Name;
506
fbf5a39b
AC
507 ------------------
508 -- Is_Less_Than --
509 ------------------
415dddc8 510
fbf5a39b 511 function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean is
415dddc8
RK
512 begin
513 if Ref1 = null then
fbf5a39b 514 return False;
415dddc8 515 elsif Ref2 = null then
fbf5a39b 516 return True;
415dddc8
RK
517 end if;
518
fbf5a39b
AC
519 if Ref1.File.File.all < Ref2.File.File.all then
520 return True;
415dddc8 521
fbf5a39b
AC
522 elsif Ref1.File.File.all = Ref2.File.File.all then
523 return (Ref1.Line < Ref2.Line
524 or else (Ref1.Line = Ref2.Line
525 and then Ref1.Column < Ref2.Column));
526 end if;
415dddc8 527
fbf5a39b
AC
528 return False;
529 end Is_Less_Than;
415dddc8 530
fbf5a39b
AC
531 ------------------
532 -- Is_Less_Than --
533 ------------------
415dddc8 534
fbf5a39b
AC
535 function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean
536 is
537 -- We cannot store the data case-insensitive in the table,
538 -- since we wouldn't be able to find the right casing for the
539 -- display later on.
415dddc8 540
fbf5a39b
AC
541 S1 : constant String := To_Lower (Decl1.Symbol);
542 S2 : constant String := To_Lower (Decl2.Symbol);
415dddc8 543
415dddc8 544 begin
fbf5a39b
AC
545 if S1 < S2 then
546 return True;
547 elsif S1 > S2 then
548 return False;
415dddc8
RK
549 end if;
550
fbf5a39b
AC
551 return Decl1.Key.all < Decl2.Key.all;
552 end Is_Less_Than;
415dddc8
RK
553
554 -------------------------
555 -- Create_Project_File --
556 -------------------------
557
fbf5a39b 558 procedure Create_Project_File (Name : String) is
415dddc8
RK
559 Obj_Dir : Unbounded_String := Null_Unbounded_String;
560 Src_Dir : Unbounded_String := Null_Unbounded_String;
fbf5a39b 561 Build_Dir : GNAT.OS_Lib.String_Access := new String'("");
415dddc8
RK
562
563 F : File_Descriptor;
564 Len : Positive;
565 File_Name : aliased String := Name & ASCII.NUL;
566
567 begin
415dddc8 568 -- Read the size of the file
fbf5a39b 569
415dddc8
RK
570 F := Open_Read (File_Name'Address, Text);
571
572 -- Project file not found
fbf5a39b 573
415dddc8
RK
574 if F /= Invalid_FD then
575 Len := Positive (File_Length (F));
576
577 declare
578 Buffer : String (1 .. Len);
579 Index : Positive := Buffer'First;
580 Last : Positive;
fbf5a39b 581
415dddc8
RK
582 begin
583 Len := Read (F, Buffer'Address, Len);
584 Close (F);
585
586 -- First, look for Build_Dir, since all the source and object
587 -- path are relative to it.
588
589 while Index <= Buffer'Last loop
590
fbf5a39b 591 -- Find the end of line
415dddc8
RK
592
593 Last := Index;
594 while Last <= Buffer'Last
595 and then Buffer (Last) /= ASCII.LF
596 and then Buffer (Last) /= ASCII.CR
597 loop
598 Last := Last + 1;
599 end loop;
600
601 if Index <= Buffer'Last - 9
602 and then Buffer (Index .. Index + 9) = "build_dir="
603 then
604 Index := Index + 10;
605 while Index <= Last
606 and then (Buffer (Index) = ' '
607 or else Buffer (Index) = ASCII.HT)
608 loop
609 Index := Index + 1;
610 end loop;
611
fbf5a39b
AC
612 Free (Build_Dir);
613 Build_Dir := new String'(Buffer (Index .. Last - 1));
415dddc8
RK
614 end if;
615
616 Index := Last + 1;
617
618 -- In case we had a ASCII.CR/ASCII.LF end of line, skip the
619 -- remaining symbol
620
621 if Index <= Buffer'Last
622 and then Buffer (Index) = ASCII.LF
623 then
624 Index := Index + 1;
625 end if;
626 end loop;
627
628 -- Now parse the source and object paths
629
630 Index := Buffer'First;
631 while Index <= Buffer'Last loop
632
fbf5a39b 633 -- Find the end of line
415dddc8
RK
634
635 Last := Index;
636 while Last <= Buffer'Last
637 and then Buffer (Last) /= ASCII.LF
638 and then Buffer (Last) /= ASCII.CR
639 loop
640 Last := Last + 1;
641 end loop;
642
643 if Index <= Buffer'Last - 7
644 and then Buffer (Index .. Index + 7) = "src_dir="
645 then
fbf5a39b
AC
646 Append (Src_Dir, Normalize_Pathname
647 (Name => Ada.Strings.Fixed.Trim
648 (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both),
649 Directory => Build_Dir.all) & Path_Separator);
415dddc8
RK
650
651 elsif Index <= Buffer'Last - 7
652 and then Buffer (Index .. Index + 7) = "obj_dir="
653 then
fbf5a39b
AC
654 Append (Obj_Dir, Normalize_Pathname
655 (Name => Ada.Strings.Fixed.Trim
656 (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both),
657 Directory => Build_Dir.all) & Path_Separator);
415dddc8
RK
658 end if;
659
660 -- In case we had a ASCII.CR/ASCII.LF end of line, skip the
661 -- remaining symbol
662 Index := Last + 1;
663
664 if Index <= Buffer'Last
665 and then Buffer (Index) = ASCII.LF
666 then
667 Index := Index + 1;
668 end if;
669 end loop;
670 end;
671 end if;
672
fbf5a39b 673 Osint.Add_Default_Search_Dirs;
415dddc8 674
fbf5a39b
AC
675 declare
676 Src : constant String := Parse_Gnatls_Src;
677 Obj : constant String := Parse_Gnatls_Obj;
678
679 begin
680 Directories := new Project_File'
681 (Src_Dir_Length => Length (Src_Dir) + Src'Length,
682 Obj_Dir_Length => Length (Obj_Dir) + Obj'Length,
683 Src_Dir => To_String (Src_Dir) & Src,
684 Obj_Dir => To_String (Obj_Dir) & Obj,
685 Src_Dir_Index => 1,
686 Obj_Dir_Index => 1,
687 Last_Obj_Dir_Start => 0);
688 end;
689
690 Free (Build_Dir);
415dddc8
RK
691 end Create_Project_File;
692
693 ---------------------
694 -- Current_Obj_Dir --
695 ---------------------
696
697 function Current_Obj_Dir return String is
698 begin
fbf5a39b
AC
699 return Directories.Obj_Dir
700 (Directories.Last_Obj_Dir_Start .. Directories.Obj_Dir_Index - 2);
415dddc8
RK
701 end Current_Obj_Dir;
702
415dddc8
RK
703 ----------------
704 -- Get_Column --
705 ----------------
706
707 function Get_Column (Decl : Declaration_Reference) return String is
708 begin
709 return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Column),
710 Ada.Strings.Left);
711 end Get_Column;
712
713 function Get_Column (Ref : Reference) return String is
714 begin
715 return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Column),
716 Ada.Strings.Left);
717 end Get_Column;
718
719 ---------------------
720 -- Get_Declaration --
721 ---------------------
722
723 function Get_Declaration
724 (File_Ref : File_Reference;
725 Line : Natural;
726 Column : Natural)
727 return Declaration_Reference
728 is
fbf5a39b 729 Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column);
415dddc8 730
fbf5a39b
AC
731 begin
732 return Entities_HTable.Get (Key'Unchecked_Access);
415dddc8
RK
733 end Get_Declaration;
734
735 ----------------------
736 -- Get_Emit_Warning --
737 ----------------------
738
739 function Get_Emit_Warning (File : File_Reference) return Boolean is
740 begin
741 return File.Emit_Warning;
742 end Get_Emit_Warning;
743
744 --------------
745 -- Get_File --
746 --------------
747
748 function Get_File
749 (Decl : Declaration_Reference;
91b1417d 750 With_Dir : Boolean := False) return String
415dddc8
RK
751 is
752 begin
753 return Get_File (Decl.Decl.File, With_Dir);
754 end Get_File;
755
756 function Get_File
757 (Ref : Reference;
91b1417d 758 With_Dir : Boolean := False) return String
415dddc8
RK
759 is
760 begin
761 return Get_File (Ref.File, With_Dir);
762 end Get_File;
763
764 function Get_File
765 (File : File_Reference;
0ae9f22f 766 With_Dir : Boolean := False;
91b1417d 767 Strip : Natural := 0) return String
415dddc8 768 is
ae71d81b 769 pragma Annotate (CodePeer, Skip_Analysis);
2d5e5d89 770 -- Disable CodePeer false positives
ae71d81b 771
fbf5a39b
AC
772 Tmp : GNAT.OS_Lib.String_Access;
773
415dddc8
RK
774 function Internal_Strip (Full_Name : String) return String;
775 -- Internal function to process the Strip parameter
776
777 --------------------
778 -- Internal_Strip --
779 --------------------
780
781 function Internal_Strip (Full_Name : String) return String is
fbf5a39b
AC
782 Unit_End : Natural;
783 Extension_Start : Natural;
784 S : Natural;
785
415dddc8
RK
786 begin
787 if Strip = 0 then
788 return Full_Name;
789 end if;
790
791 -- Isolate the file extension
792
793 Extension_Start := Full_Name'Last;
794 while Extension_Start >= Full_Name'First
795 and then Full_Name (Extension_Start) /= '.'
796 loop
797 Extension_Start := Extension_Start - 1;
798 end loop;
799
800 -- Strip the right number of subunit_names
801
fbf5a39b 802 S := Strip;
415dddc8
RK
803 Unit_End := Extension_Start - 1;
804 while Unit_End >= Full_Name'First
805 and then S > 0
806 loop
807 if Full_Name (Unit_End) = '-' then
808 S := S - 1;
809 end if;
fbf5a39b 810
415dddc8
RK
811 Unit_End := Unit_End - 1;
812 end loop;
813
814 if Unit_End < Full_Name'First then
815 return "";
816 else
817 return Full_Name (Full_Name'First .. Unit_End)
818 & Full_Name (Extension_Start .. Full_Name'Last);
819 end if;
820 end Internal_Strip;
821
fbf5a39b
AC
822 -- Start of processing for Get_File;
823
415dddc8
RK
824 begin
825 -- If we do not want the full path name
826
827 if not With_Dir then
fbf5a39b 828 return Internal_Strip (File.File.all);
415dddc8
RK
829 end if;
830
831 if File.Dir = null then
d33744e4
RD
832 if Ada.Strings.Fixed.Tail (File.File.all, 3) =
833 Osint.ALI_Suffix.all
0e47ff5c 834 then
fbf5a39b 835 Tmp := Locate_Regular_File
d33744e4 836 (Internal_Strip (File.File.all), Directories.Obj_Dir);
fbf5a39b
AC
837 else
838 Tmp := Locate_Regular_File
d33744e4 839 (File.File.all, Directories.Src_Dir);
fbf5a39b 840 end if;
415dddc8 841
fbf5a39b
AC
842 if Tmp = null then
843 File.Dir := new String'("");
415dddc8 844 else
fbf5a39b
AC
845 File.Dir := new String'(Dir_Name (Tmp.all));
846 Free (Tmp);
415dddc8
RK
847 end if;
848 end if;
849
fbf5a39b 850 return Internal_Strip (File.Dir.all & File.File.all);
415dddc8
RK
851 end Get_File;
852
853 ------------------
854 -- Get_File_Ref --
855 ------------------
856
857 function Get_File_Ref (Ref : Reference) return File_Reference is
858 begin
859 return Ref.File;
860 end Get_File_Ref;
861
862 -----------------------
863 -- Get_Gnatchop_File --
864 -----------------------
865
866 function Get_Gnatchop_File
fbf5a39b
AC
867 (File : File_Reference;
868 With_Dir : Boolean := False)
869 return String
870 is
415dddc8
RK
871 begin
872 if File.Gnatchop_File.all = "" then
873 return Get_File (File, With_Dir);
874 else
875 return File.Gnatchop_File.all;
876 end if;
877 end Get_Gnatchop_File;
878
415dddc8 879 function Get_Gnatchop_File
fbf5a39b
AC
880 (Ref : Reference;
881 With_Dir : Boolean := False)
882 return String
883 is
415dddc8
RK
884 begin
885 return Get_Gnatchop_File (Ref.File, With_Dir);
886 end Get_Gnatchop_File;
887
415dddc8 888 function Get_Gnatchop_File
fbf5a39b
AC
889 (Decl : Declaration_Reference;
890 With_Dir : Boolean := False)
891 return String
415dddc8
RK
892 is
893 begin
894 return Get_Gnatchop_File (Decl.Decl.File, With_Dir);
895 end Get_Gnatchop_File;
896
897 --------------
898 -- Get_Line --
899 --------------
900
901 function Get_Line (Decl : Declaration_Reference) return String is
902 begin
903 return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Line),
904 Ada.Strings.Left);
905 end Get_Line;
906
907 function Get_Line (Ref : Reference) return String is
908 begin
909 return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Line),
910 Ada.Strings.Left);
911 end Get_Line;
912
913 ----------------
914 -- Get_Parent --
915 ----------------
916
917 function Get_Parent
918 (Decl : Declaration_Reference)
fbf5a39b
AC
919 return Declaration_Reference
920 is
415dddc8
RK
921 begin
922 return Decl.Par_Symbol;
923 end Get_Parent;
924
925 ---------------------
926 -- Get_Source_Line --
927 ---------------------
928
929 function Get_Source_Line (Ref : Reference) return String is
930 begin
fbf5a39b
AC
931 if Ref.Source_Line /= null then
932 return Ref.Source_Line.all;
933 else
934 return "";
935 end if;
415dddc8
RK
936 end Get_Source_Line;
937
938 function Get_Source_Line (Decl : Declaration_Reference) return String is
939 begin
fbf5a39b
AC
940 if Decl.Decl.Source_Line /= null then
941 return Decl.Decl.Source_Line.all;
942 else
943 return "";
944 end if;
415dddc8
RK
945 end Get_Source_Line;
946
947 ----------------
948 -- Get_Symbol --
949 ----------------
950
951 function Get_Symbol (Decl : Declaration_Reference) return String is
952 begin
953 return Decl.Symbol;
954 end Get_Symbol;
955
956 --------------
957 -- Get_Type --
958 --------------
959
960 function Get_Type (Decl : Declaration_Reference) return Character is
961 begin
962 return Decl.Decl_Type;
963 end Get_Type;
964
fbf5a39b
AC
965 ----------
966 -- Sort --
967 ----------
415dddc8 968
fbf5a39b
AC
969 procedure Sort (Arr : in out Reference_Array) is
970 Tmp : Reference;
415dddc8 971
fbf5a39b
AC
972 function Lt (Op1, Op2 : Natural) return Boolean;
973 procedure Move (From, To : Natural);
974 -- See GNAT.Heap_Sort_G
415dddc8 975
fbf5a39b
AC
976 --------
977 -- Lt --
978 --------
415dddc8 979
fbf5a39b
AC
980 function Lt (Op1, Op2 : Natural) return Boolean is
981 begin
982 if Op1 = 0 then
983 return Is_Less_Than (Tmp, Arr (Op2));
984 elsif Op2 = 0 then
985 return Is_Less_Than (Arr (Op1), Tmp);
986 else
987 return Is_Less_Than (Arr (Op1), Arr (Op2));
988 end if;
989 end Lt;
415dddc8 990
fbf5a39b
AC
991 ----------
992 -- Move --
993 ----------
415dddc8 994
fbf5a39b
AC
995 procedure Move (From, To : Natural) is
996 begin
997 if To = 0 then
998 Tmp := Arr (From);
999 elsif From = 0 then
1000 Arr (To) := Tmp;
1001 else
1002 Arr (To) := Arr (From);
1003 end if;
1004 end Move;
415dddc8 1005
fbf5a39b 1006 package Ref_Sort is new GNAT.Heap_Sort_G (Move, Lt);
415dddc8 1007
fbf5a39b 1008 -- Start of processing for Sort
415dddc8 1009
fbf5a39b
AC
1010 begin
1011 Ref_Sort.Sort (Arr'Last);
1012 end Sort;
415dddc8 1013
fbf5a39b
AC
1014 -----------------------
1015 -- Grep_Source_Files --
1016 -----------------------
415dddc8 1017
fbf5a39b
AC
1018 procedure Grep_Source_Files is
1019 Length : Natural := 0;
1020 Decl : Declaration_Reference := Entities_HTable.Get_First;
1021 Arr : Reference_Array_Access;
1022 Index : Natural;
a6b13d32 1023 End_Index : Natural := 0;
fbf5a39b
AC
1024 Current_File : File_Reference;
1025 Current_Line : Cst_String_Access;
1026 Buffer : GNAT.OS_Lib.String_Access;
1027 Ref : Reference;
a6b13d32 1028 Line : Natural := Natural'Last;
415dddc8 1029
fbf5a39b
AC
1030 begin
1031 -- Create a temporary array, where all references will be
1032 -- sorted by files. This way, we only have to read the source
1033 -- files once.
415dddc8 1034
fbf5a39b 1035 while Decl /= null loop
415dddc8 1036
fbf5a39b 1037 -- Add 1 for the declaration itself
415dddc8 1038
fbf5a39b
AC
1039 Length := Length + References_Count (Decl, True, True, True) + 1;
1040 Decl := Entities_HTable.Get_Next;
1041 end loop;
415dddc8 1042
fbf5a39b
AC
1043 Arr := new Reference_Array (1 .. Length);
1044 Index := Arr'First;
415dddc8 1045
fbf5a39b
AC
1046 Decl := Entities_HTable.Get_First;
1047 while Decl /= null loop
1048 Store_References (Decl, True, True, True, True, Arr.all, Index);
1049 Decl := Entities_HTable.Get_Next;
1050 end loop;
415dddc8 1051
fbf5a39b 1052 Sort (Arr.all);
415dddc8 1053
fbf5a39b
AC
1054 -- Now traverse the whole array and find the appropriate source
1055 -- lines.
415dddc8 1056
fbf5a39b
AC
1057 for R in Arr'Range loop
1058 Ref := Arr (R);
415dddc8 1059
fbf5a39b
AC
1060 if Ref.File /= Current_File then
1061 Free (Buffer);
1062 begin
1063 Read_File (Get_File (Ref.File, With_Dir => True), Buffer);
1064 End_Index := Buffer'First - 1;
1065 Line := 0;
1066 exception
1067 when Ada.Text_IO.Name_Error | Ada.Text_IO.End_Error =>
1068 Line := Natural'Last;
1069 end;
1070 Current_File := Ref.File;
1071 end if;
415dddc8 1072
fbf5a39b 1073 if Ref.Line > Line then
415dddc8 1074
fbf5a39b
AC
1075 -- Do not free Current_Line, it is referenced by the last
1076 -- Ref we processed.
415dddc8 1077
fbf5a39b
AC
1078 loop
1079 Index := End_Index + 1;
415dddc8 1080
fbf5a39b
AC
1081 loop
1082 End_Index := End_Index + 1;
1083 exit when End_Index > Buffer'Last
1084 or else Buffer (End_Index) = ASCII.LF;
1085 end loop;
415dddc8 1086
fbf5a39b 1087 -- Skip spaces at beginning of line
415dddc8 1088
fbf5a39b
AC
1089 while Index < End_Index and then
1090 (Buffer (Index) = ' ' or else Buffer (Index) = ASCII.HT)
415dddc8 1091 loop
fbf5a39b 1092 Index := Index + 1;
415dddc8
RK
1093 end loop;
1094
fbf5a39b
AC
1095 Line := Line + 1;
1096 exit when Ref.Line = Line;
1097 end loop;
07fc65c4 1098
fbf5a39b
AC
1099 Current_Line := new String'(Buffer (Index .. End_Index - 1));
1100 end if;
415dddc8 1101
fbf5a39b
AC
1102 Ref.Source_Line := Current_Line;
1103 end loop;
415dddc8 1104
fbf5a39b
AC
1105 Free (Buffer);
1106 Free (Arr);
1107 end Grep_Source_Files;
415dddc8 1108
fbf5a39b
AC
1109 ---------------
1110 -- Read_File --
1111 ---------------
415dddc8 1112
fbf5a39b
AC
1113 procedure Read_File
1114 (File_Name : String;
1115 Contents : out GNAT.OS_Lib.String_Access)
1116 is
1117 Name_0 : constant String := File_Name & ASCII.NUL;
1118 FD : constant File_Descriptor := Open_Read (Name_0'Address, Binary);
1119 Length : Natural;
415dddc8 1120
fbf5a39b
AC
1121 begin
1122 if FD = Invalid_FD then
1123 raise Ada.Text_IO.Name_Error;
1124 end if;
1125
1126 -- Include room for EOF char
1127
1128 Length := Natural (File_Length (FD));
1129
1130 declare
1131 Buffer : String (1 .. Length + 1);
1132 This_Read : Integer;
1133 Read_Ptr : Natural := 1;
415dddc8
RK
1134
1135 begin
fbf5a39b
AC
1136 loop
1137 This_Read := Read (FD,
1138 A => Buffer (Read_Ptr)'Address,
1139 N => Length + 1 - Read_Ptr);
1140 Read_Ptr := Read_Ptr + Integer'Max (This_Read, 0);
1141 exit when This_Read <= 0;
415dddc8 1142 end loop;
415dddc8 1143
fbf5a39b
AC
1144 Buffer (Read_Ptr) := EOF;
1145 Contents := new String'(Buffer (1 .. Read_Ptr));
78f8727c
RD
1146
1147 if Read_Ptr /= Length + 1 then
1148 raise Ada.Text_IO.End_Error;
1149 end if;
1150
fbf5a39b
AC
1151 Close (FD);
1152 end;
1153 end Read_File;
415dddc8
RK
1154
1155 -----------------------
1156 -- Longest_File_Name --
1157 -----------------------
1158
1159 function Longest_File_Name return Natural is
1160 begin
fbf5a39b 1161 return Longest_File_Name_In_Table;
415dddc8
RK
1162 end Longest_File_Name;
1163
1164 -----------
1165 -- Match --
1166 -----------
1167
1168 function Match
1169 (File : File_Reference;
1170 Line : Natural;
1171 Column : Natural)
1172 return Boolean
1173 is
1174 Ref : Ref_In_File_Ptr := File.Lines;
1175
1176 begin
1177 while Ref /= null loop
1178 if (Ref.Line = 0 or else Ref.Line = Line)
1179 and then (Ref.Column = 0 or else Ref.Column = Column)
1180 then
1181 return True;
1182 end if;
1183
1184 Ref := Ref.Next;
1185 end loop;
1186
1187 return False;
1188 end Match;
1189
1190 -----------
1191 -- Match --
1192 -----------
1193
1194 function Match (Decl : Declaration_Reference) return Boolean is
1195 begin
1196 return Decl.Match;
1197 end Match;
1198
1199 ----------
1200 -- Next --
1201 ----------
1202
fbf5a39b 1203 function Next (E : File_Reference) return File_Reference is
415dddc8 1204 begin
fbf5a39b 1205 return E.Next;
415dddc8
RK
1206 end Next;
1207
fbf5a39b 1208 function Next (E : Declaration_Reference) return Declaration_Reference is
415dddc8 1209 begin
fbf5a39b 1210 return E.Next;
415dddc8
RK
1211 end Next;
1212
1213 ------------------
1214 -- Next_Obj_Dir --
1215 ------------------
1216
1217 function Next_Obj_Dir return String is
fbf5a39b
AC
1218 First : constant Integer := Directories.Obj_Dir_Index;
1219 Last : Integer;
415dddc8
RK
1220
1221 begin
fbf5a39b
AC
1222 Last := Directories.Obj_Dir_Index;
1223
415dddc8
RK
1224 if Last > Directories.Obj_Dir_Length then
1225 return String'(1 .. 0 => ' ');
1226 end if;
1227
fbf5a39b 1228 while Directories.Obj_Dir (Last) /= Path_Separator loop
415dddc8
RK
1229 Last := Last + 1;
1230 end loop;
1231
1232 Directories.Obj_Dir_Index := Last + 1;
1233 Directories.Last_Obj_Dir_Start := First;
1234 return Directories.Obj_Dir (First .. Last - 1);
1235 end Next_Obj_Dir;
1236
415dddc8
RK
1237 -------------------------
1238 -- Next_Unvisited_File --
1239 -------------------------
1240
1241 function Next_Unvisited_File return File_Reference is
fbf5a39b
AC
1242 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1243 (Unvisited_Files_Record, Unvisited_Files_Access);
415dddc8 1244
fbf5a39b
AC
1245 Ref : File_Reference;
1246 Tmp : Unvisited_Files_Access;
415dddc8 1247
fbf5a39b
AC
1248 begin
1249 if Unvisited_Files = null then
1250 return Empty_File;
1251 else
1252 Tmp := Unvisited_Files;
1253 Ref := Unvisited_Files.File;
1254 Unvisited_Files := Unvisited_Files.Next;
1255 Unchecked_Free (Tmp);
1256 return Ref;
1257 end if;
415dddc8
RK
1258 end Next_Unvisited_File;
1259
fbf5a39b
AC
1260 ----------------------
1261 -- Parse_Gnatls_Src --
1262 ----------------------
415dddc8 1263
fbf5a39b
AC
1264 function Parse_Gnatls_Src return String is
1265 Length : Natural;
415dddc8 1266
fbf5a39b
AC
1267 begin
1268 Length := 0;
415dddc8
RK
1269 for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1270 if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
fbf5a39b 1271 Length := Length + 2;
415dddc8 1272 else
fbf5a39b 1273 Length := Length + Osint.Dir_In_Src_Search_Path (J)'Length + 1;
415dddc8
RK
1274 end if;
1275 end loop;
1276
fbf5a39b
AC
1277 declare
1278 Result : String (1 .. Length);
1279 L : Natural;
1280
1281 begin
1282 L := Result'First;
1283 for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1284 if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1285 Result (L .. L + 1) := "." & Path_Separator;
1286 L := L + 2;
1287
1288 else
1289 Result (L .. L + Osint.Dir_In_Src_Search_Path (J)'Length - 1) :=
1290 Osint.Dir_In_Src_Search_Path (J).all;
1291 L := L + Osint.Dir_In_Src_Search_Path (J)'Length;
1292 Result (L) := Path_Separator;
1293 L := L + 1;
1294 end if;
1295 end loop;
1296
1297 return Result;
1298 end;
1299 end Parse_Gnatls_Src;
1300
1301 ----------------------
1302 -- Parse_Gnatls_Obj --
1303 ----------------------
1304
1305 function Parse_Gnatls_Obj return String is
1306 Length : Natural;
1307
1308 begin
1309 Length := 0;
415dddc8
RK
1310 for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1311 if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
fbf5a39b 1312 Length := Length + 2;
415dddc8 1313 else
fbf5a39b 1314 Length := Length + Osint.Dir_In_Obj_Search_Path (J)'Length + 1;
415dddc8
RK
1315 end if;
1316 end loop;
fbf5a39b
AC
1317
1318 declare
1319 Result : String (1 .. Length);
1320 L : Natural;
1321
1322 begin
1323 L := Result'First;
1324 for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1325 if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1326 Result (L .. L + 1) := "." & Path_Separator;
1327 L := L + 2;
1328 else
1329 Result (L .. L + Osint.Dir_In_Obj_Search_Path (J)'Length - 1) :=
1330 Osint.Dir_In_Obj_Search_Path (J).all;
1331 L := L + Osint.Dir_In_Obj_Search_Path (J)'Length;
1332 Result (L) := Path_Separator;
1333 L := L + 1;
1334 end if;
1335 end loop;
1336
1337 return Result;
1338 end;
1339 end Parse_Gnatls_Obj;
415dddc8
RK
1340
1341 -------------------
1342 -- Reset_Obj_Dir --
1343 -------------------
1344
1345 procedure Reset_Obj_Dir is
1346 begin
1347 Directories.Obj_Dir_Index := 1;
1348 end Reset_Obj_Dir;
1349
415dddc8
RK
1350 -----------------------
1351 -- Set_Default_Match --
1352 -----------------------
1353
1354 procedure Set_Default_Match (Value : Boolean) is
1355 begin
1356 Default_Match := Value;
1357 end Set_Default_Match;
1358
fbf5a39b
AC
1359 ----------
1360 -- Free --
1361 ----------
415dddc8 1362
fbf5a39b
AC
1363 procedure Free (Str : in out Cst_String_Access) is
1364 function Convert is new Ada.Unchecked_Conversion
1365 (Cst_String_Access, GNAT.OS_Lib.String_Access);
1366
1367 S : GNAT.OS_Lib.String_Access := Convert (Str);
1368
1369 begin
1370 Free (S);
1371 Str := null;
1372 end Free;
1373
1374 ---------------------
1375 -- Reset_Directory --
1376 ---------------------
1377
1378 procedure Reset_Directory (File : File_Reference) is
415dddc8 1379 begin
fbf5a39b
AC
1380 Free (File.Dir);
1381 end Reset_Directory;
415dddc8
RK
1382
1383 -------------------
1384 -- Set_Unvisited --
1385 -------------------
1386
fbf5a39b
AC
1387 procedure Set_Unvisited (File_Ref : File_Reference) is
1388 F : constant String := Get_File (File_Ref, With_Dir => False);
415dddc8
RK
1389
1390 begin
fbf5a39b
AC
1391 File_Ref.Visited := False;
1392
2d5e5d89
AC
1393 -- Do not add a source file to the list. This is true for gnatxref
1394 -- gnatfind, so good enough.
fbf5a39b
AC
1395
1396 if F'Length > 4
0e47ff5c 1397 and then F (F'Last - 3 .. F'Last) = "." & Osint.ALI_Suffix.all
fbf5a39b
AC
1398 then
1399 Unvisited_Files := new Unvisited_Files_Record'
1400 (File => File_Ref,
1401 Next => Unvisited_Files);
1402 end if;
1403 end Set_Unvisited;
1404
1405 ----------------------
1406 -- Get_Declarations --
1407 ----------------------
1408
1409 function Get_Declarations
1410 (Sorted : Boolean := True)
1411 return Declaration_Array_Access
1412 is
adc04486 1413 Arr : constant Declaration_Array_Access :=
fbf5a39b
AC
1414 new Declaration_Array (1 .. Entities_Count);
1415 Decl : Declaration_Reference := Entities_HTable.Get_First;
1416 Index : Natural := Arr'First;
1417 Tmp : Declaration_Reference;
1418
1419 procedure Move (From : Natural; To : Natural);
1420 function Lt (Op1, Op2 : Natural) return Boolean;
1421 -- See GNAT.Heap_Sort_G
1422
1423 --------
1424 -- Lt --
1425 --------
1426
1427 function Lt (Op1, Op2 : Natural) return Boolean is
1428 begin
1429 if Op1 = 0 then
1430 return Is_Less_Than (Tmp, Arr (Op2));
1431 elsif Op2 = 0 then
1432 return Is_Less_Than (Arr (Op1), Tmp);
1433 else
1434 return Is_Less_Than (Arr (Op1), Arr (Op2));
415dddc8 1435 end if;
fbf5a39b
AC
1436 end Lt;
1437
1438 ----------
1439 -- Move --
1440 ----------
1441
1442 procedure Move (From : Natural; To : Natural) is
1443 begin
1444 if To = 0 then
1445 Tmp := Arr (From);
1446 elsif From = 0 then
1447 Arr (To) := Tmp;
1448 else
1449 Arr (To) := Arr (From);
1450 end if;
1451 end Move;
1452
1453 package Decl_Sort is new GNAT.Heap_Sort_G (Move, Lt);
415dddc8 1454
fbf5a39b
AC
1455 -- Start of processing for Get_Declarations
1456
1457 begin
1458 while Decl /= null loop
1459 Arr (Index) := Decl;
1460 Index := Index + 1;
1461 Decl := Entities_HTable.Get_Next;
415dddc8 1462 end loop;
fbf5a39b
AC
1463
1464 if Sorted and then Arr'Length /= 0 then
1465 Decl_Sort.Sort (Entities_Count);
1466 end if;
1467
1468 return Arr;
1469 end Get_Declarations;
1470
1471 ----------------------
1472 -- References_Count --
1473 ----------------------
1474
1475 function References_Count
1476 (Decl : Declaration_Reference;
1477 Get_Reads : Boolean := False;
1478 Get_Writes : Boolean := False;
1479 Get_Bodies : Boolean := False)
1480 return Natural
1481 is
1482 function List_Length (E : Reference) return Natural;
1483 -- Return the number of references in E
1484
1485 -----------------
1486 -- List_Length --
1487 -----------------
1488
1489 function List_Length (E : Reference) return Natural is
1490 L : Natural := 0;
1491 E1 : Reference := E;
1492
1493 begin
1494 while E1 /= null loop
1495 L := L + 1;
1496 E1 := E1.Next;
1497 end loop;
1498
1499 return L;
1500 end List_Length;
1501
1502 Length : Natural := 0;
1503
1504 -- Start of processing for References_Count
1505
1506 begin
1507 if Get_Reads then
1508 Length := List_Length (Decl.Ref_Ref);
1509 end if;
1510
1511 if Get_Writes then
1512 Length := Length + List_Length (Decl.Modif_Ref);
1513 end if;
1514
1515 if Get_Bodies then
1516 Length := Length + List_Length (Decl.Body_Ref);
1517 end if;
1518
1519 return Length;
1520 end References_Count;
1521
1522 ----------------------
1523 -- Store_References --
1524 ----------------------
1525
1526 procedure Store_References
1527 (Decl : Declaration_Reference;
1528 Get_Writes : Boolean := False;
1529 Get_Reads : Boolean := False;
1530 Get_Bodies : Boolean := False;
1531 Get_Declaration : Boolean := False;
1532 Arr : in out Reference_Array;
1533 Index : in out Natural)
1534 is
1535 procedure Add (List : Reference);
1536 -- Add all the references in List to Arr
1537
1538 ---------
1539 -- Add --
1540 ---------
1541
1542 procedure Add (List : Reference) is
1543 E : Reference := List;
1544 begin
1545 while E /= null loop
1546 Arr (Index) := E;
1547 Index := Index + 1;
1548 E := E.Next;
1549 end loop;
1550 end Add;
1551
1552 -- Start of processing for Store_References
1553
1554 begin
1555 if Get_Declaration then
1556 Add (Decl.Decl);
1557 end if;
1558
1559 if Get_Reads then
1560 Add (Decl.Ref_Ref);
1561 end if;
1562
1563 if Get_Writes then
1564 Add (Decl.Modif_Ref);
1565 end if;
1566
1567 if Get_Bodies then
1568 Add (Decl.Body_Ref);
1569 end if;
1570 end Store_References;
1571
1572 --------------------
1573 -- Get_References --
1574 --------------------
1575
1576 function Get_References
1577 (Decl : Declaration_Reference;
1578 Get_Reads : Boolean := False;
1579 Get_Writes : Boolean := False;
1580 Get_Bodies : Boolean := False)
1581 return Reference_Array_Access
1582 is
1583 Length : constant Natural :=
1584 References_Count (Decl, Get_Reads, Get_Writes, Get_Bodies);
1585
1586 Arr : constant Reference_Array_Access :=
1587 new Reference_Array (1 .. Length);
1588
1589 Index : Natural := Arr'First;
1590
1591 begin
1592 Store_References
1593 (Decl => Decl,
1594 Get_Writes => Get_Writes,
1595 Get_Reads => Get_Reads,
1596 Get_Bodies => Get_Bodies,
1597 Get_Declaration => False,
1598 Arr => Arr.all,
1599 Index => Index);
1600
1601 if Arr'Length /= 0 then
1602 Sort (Arr.all);
1603 end if;
1604
1605 return Arr;
1606 end Get_References;
1607
1608 ----------
1609 -- Free --
1610 ----------
1611
1612 procedure Free (Arr : in out Reference_Array_Access) is
1613 procedure Internal is new Ada.Unchecked_Deallocation
1614 (Reference_Array, Reference_Array_Access);
1615 begin
1616 Internal (Arr);
1617 end Free;
1618
1619 ------------------
1620 -- Is_Parameter --
1621 ------------------
1622
1623 function Is_Parameter (Decl : Declaration_Reference) return Boolean is
1624 begin
1625 return Decl.Is_Parameter;
1626 end Is_Parameter;
415dddc8
RK
1627
1628end Xr_Tabls;