1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
|
------------------------------------------------------------------------------
-- C O D E P E E R / S P A R K --
-- --
-- Copyright (C) 2015-2022, AdaCore --
-- --
-- This is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. This software is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
-- TABILITY 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 distributed with this software; see file --
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy --
-- of the license. --
-- --
------------------------------------------------------------------------------
pragma Ada_2012;
with Ada.Containers; use Ada.Containers;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
package SA_Messages is
-- This package can be used for reading/writing a file containing a
-- sequence of static anaysis results. Each element can describe a runtime
-- check whose outcome has been statically determined, or it might be a
-- warning or diagnostic message. It is expected that typically CodePeer
-- will do the writing and SPARK will do the reading; this will allow SPARK
-- to get the benefit of CodePeer's analysis.
--
-- Each item is represented as a pair consisting of a message and an
-- associated source location. Source locations may refer to a location
-- within the expansion of an instance of a generic; this is represented
-- by combining the corresponding location within the generic with the
-- location of the instance (repeated if the instance itself occurs within
-- a generic). In addition, the type Iteration_Id is intended for use in
-- distinguishing messages which refer to a specific iteration of a loop
-- (this case can arise, for example, if CodePeer chooses to unroll a
-- for-loop). This data structure is only general enough to support the
-- kinds of unrolling that are currently planned for CodePeer. For
-- example, an Iteration_Id can only identify an iteration of the nearest
-- enclosing loop of the associated File/Line/Column source location.
-- This is not a problem because CodePeer doesn't unroll loops which
-- contain other loops.
type Message_Kind is (
-- Check kinds
Array_Index_Check,
Divide_By_Zero_Check,
Tag_Check,
Discriminant_Check,
Range_Check,
Overflow_Check,
Assertion_Check,
-- Warning kinds
Suspicious_Range_Precondition_Warning,
Suspicious_First_Precondition_Warning,
Suspicious_Input_Warning,
Suspicious_Constant_Operation_Warning,
Unread_In_Out_Parameter_Warning,
Unassigned_In_Out_Parameter_Warning,
Non_Analyzed_Call_Warning,
Procedure_Does_Not_Return_Warning,
Check_Fails_On_Every_Call_Warning,
Unknown_Call_Warning,
Dead_Store_Warning,
Dead_Outparam_Store_Warning,
Potentially_Dead_Store_Warning,
Same_Value_Dead_Store_Warning,
Dead_Block_Warning,
Infinite_Loop_Warning,
Dead_Edge_Warning,
Plain_Dead_Edge_Warning,
True_Dead_Edge_Warning,
False_Dead_Edge_Warning,
True_Condition_Dead_Edge_Warning,
False_Condition_Dead_Edge_Warning,
Unrepeatable_While_Loop_Warning,
Dead_Block_Continuation_Warning,
Local_Lock_Of_Global_Object_Warning,
Analyzed_Module_Warning,
Non_Analyzed_Module_Warning,
Non_Analyzed_Procedure_Warning,
Incompletely_Analyzed_Procedure_Warning);
-- Assertion_Check includes checks for user-defined PPCs (both specific
-- and class-wide), Assert pragma checks, subtype predicate checks,
-- type invariant checks (specific and class-wide), and checks for
-- implementation-defined assertions such as Assert_And_Cut, Assume,
-- Contract_Cases, Default_Initial_Condition, Initial_Condition,
-- Loop_Invariant, Loop_Variant, Refined_Post, and Subprogram_Variant.
--
-- It might be nice to distinguish these different kinds of assertions
-- as is done in SPARK's VC_Kind enumeration type, but any distinction
-- which isn't already present in CP's BE_Message_Subkind enumeration type
-- would require more work on the CP side.
--
-- The warning kinds are pretty much a copy of the set of
-- Be_Message_Subkind values for which CP's Is_Warning predicate returns
-- True; see descriptive comment for each in CP's message_kinds.ads .
subtype Check_Kind is Message_Kind
range Array_Index_Check .. Assertion_Check;
subtype Warning_Kind is Message_Kind
range Message_Kind'Succ (Check_Kind'Last) .. Message_Kind'Last;
-- Possible outcomes of the static analysis of a runtime check
--
-- Not_Statically_Known_With_Low_Severity could be used instead of of
-- Not_Statically_Known if there is some reason to believe that (although
-- the tool couldn't prove it) the check is likely to always pass (in CP
-- terms, if the corresponding CP message has severity Low as opposed to
-- Medium). It's not clear yet whether SPARK will care about this
-- distinction.
type SA_Check_Result is
(Statically_Known_Success,
Not_Statically_Known_With_Low_Severity,
Not_Statically_Known,
Statically_Known_Failure);
type SA_Message (Kind : Message_Kind := Message_Kind'Last) is record
case Kind is
when Check_Kind =>
Check_Result : SA_Check_Result;
when Warning_Kind =>
null;
end case;
end record;
type Source_Location_Or_Null (<>) is private;
Null_Location : constant Source_Location_Or_Null;
subtype Source_Location is Source_Location_Or_Null with
Dynamic_Predicate => Source_Location /= Null_Location;
type Line_Number is new Positive;
type Column_Number is new Positive;
function File_Name (Location : Source_Location) return String;
function File_Name (Location : Source_Location) return Unbounded_String;
function Line (Location : Source_Location) return Line_Number;
function Column (Location : Source_Location) return Column_Number;
type Iteration_Kind is (None, Initial, Subsequent, Numbered);
-- None is for the usual no-unrolling case.
-- Initial and Subsequent are for use in the case where only the first
-- iteration of a loop (or some part thereof, such as the termination
-- test of a while-loop) is unrolled.
-- Numbered is for use in the case where a for-loop with a statically
-- known number of iterations is fully unrolled.
subtype Iteration_Number is Integer range 1 .. 255;
subtype Iteration_Total is Integer range 2 .. 255;
type Iteration_Id (Kind : Iteration_Kind := None) is record
case Kind is
when Numbered =>
Number : Iteration_Number;
Of_Total : Iteration_Total;
when others =>
null;
end case;
end record;
function Iteration (Location : Source_Location) return Iteration_Id;
function Enclosing_Instance
(Location : Source_Location) return Source_Location_Or_Null;
-- For a source location occurring within the expansion of an instance of a
-- generic unit, the Line, Column, and File_Name selectors will indicate a
-- location within the generic; the Enclosing_Instance selector yields the
-- location of the declaration of the instance.
function Make
(File_Name : String;
Line : Line_Number;
Column : Column_Number;
Iteration : Iteration_Id;
Enclosing_Instance : Source_Location_Or_Null) return Source_Location;
-- Constructor
type Message_And_Location (<>) is private;
function Location (Item : Message_And_Location) return Source_Location;
function Message (Item : Message_And_Location) return SA_Message;
function Make_Msg_Loc
(Msg : SA_Message;
Loc : Source_Location) return Message_And_Location;
-- Selectors
function "<" (Left, Right : Message_And_Location) return Boolean;
function Hash (Key : Message_And_Location) return Hash_Type;
-- Actuals for container instances
File_Extension : constant String; -- ".json" (but could change in future)
-- Clients may wish to use File_Extension in constructing
-- File_Name parameters for calls to Open.
package Writing is
function Is_Open return Boolean;
procedure Open (File_Name : String) with
Precondition => not Is_Open,
Postcondition => Is_Open;
-- Behaves like Text_IO.Create with respect to error cases
procedure Write (Message : SA_Message; Location : Source_Location);
procedure Close with
Precondition => Is_Open,
Postcondition => not Is_Open;
-- Behaves like Text_IO.Close with respect to error cases
end Writing;
package Reading is
function Is_Open return Boolean;
procedure Open (File_Name : String; Full_Path : Boolean := True) with
Precondition => not Is_Open,
Postcondition => Is_Open;
-- Behaves like Text_IO.Open with respect to error cases
function Done return Boolean with
Precondition => Is_Open;
function Get return Message_And_Location with
Precondition => not Done;
procedure Close with
Precondition => Is_Open,
Postcondition => not Is_Open;
-- Behaves like Text_IO.Close with respect to error cases
end Reading;
private
type Simple_Source_Location is record
File_Name : Unbounded_String := Null_Unbounded_String;
Line : Line_Number := Line_Number'Last;
Column : Column_Number := Column_Number'Last;
Iteration : Iteration_Id := (Kind => None);
end record;
type Source_Locations is
array (Natural range <>) of Simple_Source_Location;
type Source_Location_Or_Null (Count : Natural) is record
Locations : Source_Locations (1 .. Count);
end record;
Null_Location : constant Source_Location_Or_Null :=
(Count => 0, Locations => (others => <>));
type Message_And_Location (Count : Positive) is record
Message : SA_Message;
Location : Source_Location (Count => Count);
end record;
File_Extension : constant String := ".json";
end SA_Messages;
|