asar coverage - build #227


src/asar/
File: src/asar/warnings.cpp
Date: 2024-03-13 12:34:57
Lines:
72/80
90.0%
Functions:
8/9
88.9%
Branches:
46/64
71.9%

Line Branch Exec Source
1 #include "warnings.h"
2
3 #include "asar.h"
4 #include <assert.h>
5 #include <stdarg.h>
6
7 #include "interface-shared.h"
8
9 static int asar_num_warnings = 0;
10 bool suppress_all_warnings = false;
11
12 struct asar_warning_mapping
13 {
14 asar_warning_id warnid;
15 const char* name;
16 const char* message;
17 bool enabled;
18 bool enabled_default;
19
20 3200 asar_warning_mapping(asar_warning_id inwarnid, const char *iname, const char* inmessage, bool inenabled = true)
21 3200 {
22 3200 ++asar_num_warnings;
23
24 3200 warnid = inwarnid;
25 3200 name = iname;
26 3200 message = inmessage;
27 3200 enabled = inenabled;
28 3200 enabled_default = inenabled;
29
30 // RPG Hacker: Sanity check. This makes sure that the order
31 // of entries in asar_warnings matches with the order of
32 // constants in asar_warning_id. This is important because
33 // we access asar_warnings as an array.
34 // Would love to do this via static_assert(), but can't
35 // think of a way to do so.
36
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3200 times.
3200 assert(warnid - warning_id_start == asar_num_warnings);
37 3200 }
38 };
39
40 // Keep in sync with asar_warning_id.
41 // Both, enum mapping and order, must match.
42 #define WRN(name) warning_id_ ## name, "W" #name
43 static asar_warning_mapping asar_warnings[] =
44 {
45 { WRN(relative_path_used), "Relative %s path passed to asar_patch_ex() - please use absolute paths only to prevent undefined behavior!" },
46
47 { WRN(rom_too_short), "ROM is too short to have a title. (Expected '%s')" },
48 { WRN(rom_title_incorrect), "ROM title is incorrect. Expected '%s', got '%s'." },
49
50 { WRN(65816_yy_x_does_not_exist), "($yy),x does not exist, assuming $yy,x." },
51 { WRN(65816_xx_y_assume_16_bit), "%s $xx,y is not valid with 8-bit parameters, assuming 16-bit." },
52 { WRN(spc700_assuming_8_bit), "This opcode does not exist with 16-bit parameters, assuming 8-bit." },
53
54 { WRN(cross_platform_path), "This patch may not assemble cleanly on all platforms. Please use / instead." },
55
56 { WRN(missing_org), "Missing org or freespace command." },
57 { WRN(set_middle_byte), "It would be wise to set the 008000 bit of this address." },
58
59 { WRN(unrecognized_special_command), "Unrecognized special command - your version of Asar might be outdated." },
60
61 { WRN(freespace_leaked), "This freespace appears to be leaked." },
62
63 { WRN(warn_command), "warn command%s" },
64
65 { WRN(implicitly_sized_immediate), "Implicitly sized immediate.", false },
66
67 { WRN(xkas_deprecated), "xkas support is being deprecated and will be removed in a future version of Asar. Please use an older version of Asar (<=1.50) if you need it." },
68 { WRN(xkas_eat_parentheses), "xkas compatibility warning: Unlike xkas, Asar does not eat parentheses after defines." },
69 { WRN(xkas_label_access), "xkas compatibility warning: Label access is always 24bit in emulation mode, but may be 16bit in native mode." },
70 { WRN(xkas_warnpc_relaxed), "xkas conversion warning : warnpc is relaxed one byte in Asar." },
71 { WRN(xkas_style_conditional), "xkas-style conditional compilation detected. Please use the if command instead." },
72 { WRN(xkas_patch), "If you want to assemble an xkas patch, add ;@xkas at the top or you may run into a couple of problems." },
73 { WRN(xkas_incsrc_relative), "xkas compatibility warning: incsrc and incbin look for files relative to the patch in Asar, but xkas looks relative to the assembler." },
74 { WRN(convert_to_asar), "Convert the patch to native Asar format instead of making an Asar-only xkas patch." },
75
76 { WRN(fixed_deprecated), "the 'fixed' parameter on freespace/freecode/freedata is deprecated - please use 'static' instead." },
77
78 { WRN(autoclear_deprecated), "'autoclear' is deprecated - please use 'autoclean' instead." },
79
80 { WRN(check_memory_file), "Accessing file '%s' which is not in memory while W%d is enabled.", false },
81
82 { WRN(if_not_condition_deprecated), "'if !condition' is deprecated - please use 'if not(condition)' instead." },
83
84 { WRN(function_redefined), "Function '%s' redefined." },
85
86 { WRN(datasize_last_label), "Datasize used on last detected label '%s'." },
87 { WRN(datasize_exceeds_size), "Datasize exceeds 0xFFFF for label '%s'." },
88
89 { WRN(mapper_already_set), "A mapper has already been selected." },
90 { WRN(feature_deprecated), "DEPRECATION NOTIFICATION: Feature \"%s\" is deprecated and will be REMOVED in the future. Please update your code to conform to newer styles. Suggested work around: %s." },
91
92 { WRN(byte_order_mark_utf8), "UTF-8 byte order mark detected and skipped." },
93 { WRN(optimization_settings), "In Asar 2.0, the default optimization settings will change to `optimize dp always` and `optimize address mirrors`, which changes this instruction's argument from %d to %d bytes. Either specify the desired settings manually or use explicit length suffixes to silence this warning." },
94 };
95
96 // RPG Hacker: Sanity check. This makes sure that the element count of asar_warnings
97 // matches with the number of constants in asar_warning_id. This is important, because
98 // we are going to access asar_warnings as an array.
99 static_assert(sizeof(asar_warnings) / sizeof(asar_warnings[0]) == warning_id_count, "asar_warnings and asar_warning_id are not in sync");
100
101 898 void asar_throw_warning(int whichpass, asar_warning_id warnid, ...)
102 {
103
4/4
✓ Branch 0 taken 408 times.
✓ Branch 1 taken 490 times.
✓ Branch 2 taken 394 times.
✓ Branch 3 taken 14 times.
898 if (pass == whichpass && !suppress_all_warnings)
104 {
105
2/4
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197 times.
✗ Branch 3 not taken.
197 assert(warnid > warning_id_start && warnid < warning_id_end);
106
107 394 const asar_warning_mapping& warning = asar_warnings[warnid - warning_id_start - 1];
108
109
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 298 times.
394 if (warning.enabled)
110 {
111 48 char warning_buffer[1024];
112 48 va_list args;
113 96 va_start(args, warnid);
114
115 #if defined(__clang__)
116 # pragma clang diagnostic push
117 // "format string is not a literal".
118 // The pointer we're passing here should always point to a string literal,
119 // thus, I think, we can safely ignore this here.
120 # pragma clang diagnostic ignored "-Wformat-nonliteral"
121 #endif
122
123 96 vsnprintf(warning_buffer, sizeof(warning_buffer), warning.message, args);
124
125 #if defined(__clang__)
126 # pragma clang diagnostic pop
127 #endif
128
129 96 va_end(args);
130
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
96 warn((int)warnid, warning_buffer);
131 }
132 }
133 898 }
134
135 96 const char* get_warning_name(asar_warning_id warnid)
136 {
137
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
48 assert(warnid > warning_id_start && warnid < warning_id_end);
138
139 96 const asar_warning_mapping& warning = asar_warnings[warnid - warning_id_start - 1];
140
141 96 return warning.name;
142 }
143
144
145
146 72 void set_warning_enabled(asar_warning_id warnid, bool enabled)
147 {
148
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
36 assert(warnid > warning_id_start && warnid < warning_id_end);
149
150 72 asar_warning_mapping& warning = asar_warnings[warnid - warning_id_start - 1];
151
152 72 warning.enabled = enabled;
153 72 }
154
155 72 asar_warning_id parse_warning_id_from_string(const char* string, int warn_pass)
156 {
157 36 const char* pos = string;
158
159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 if (pos == nullptr)
160 {
161 return warning_id_end;
162 }
163
164
165
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
72 if (pos[0] == 'w' || pos[0] == 'W')
166 {
167 72 ++pos;
168 }
169
2/2
✓ Branch 0 taken 1404 times.
✓ Branch 1 taken 6 times.
1410 for(int i = 0; i < warning_id_end-warning_id_start-1; i++)
170 {
171
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 1338 times.
1404 if(!stricmpwithlower(pos, asar_warnings[i].name+1))
172 {
173 66 return asar_warnings[i].warnid;
174 }
175 }
176 6 char* endpos = nullptr;
177 6 int numid = (int)strtol(pos, &endpos, 10);
178
179
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (endpos == nullptr || endpos[0] != '\0')
180 {
181 return warning_id_end;
182 }
183
184 3 asar_warning_id warnid = (asar_warning_id)numid;
185
186
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
6 if (warnid <= warning_id_start || warnid >= warning_id_end)
187 {
188 return warning_id_end;
189 }
190
191
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 asar_throw_warning(warn_pass, warning_id_feature_deprecated, "Numerical warnings", "Please transition to Wwarning_name");
192 3 return warnid;
193 }
194
195 void reset_warnings_to_default()
196 {
197 for (int i = (int)(warning_id_start + 1); i < (int)warning_id_end; ++i)
198 {
199 asar_warning_mapping& warning = asar_warnings[i - (int)warning_id_start - 1];
200
201 warning.enabled = warning.enabled_default;
202 }
203 }
204
205 struct warnings_state
206 {
207 bool enabled[warning_id_count];
208 };
209
210 static autoarray<warnings_state> warnings_state_stack;
211 static warnings_state main_warnings_state;
212
213 610 void push_warnings(bool warnings_command)
214 {
215 305 warnings_state current_state;
216
217
2/2
✓ Branch 0 taken 19520 times.
✓ Branch 1 taken 610 times.
20130 for (int i = 0; i < (int)warning_id_count; ++i)
218 {
219 19520 current_state.enabled[i] = asar_warnings[i].enabled;
220 }
221
222
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 592 times.
610 if (warnings_command)
223 {
224
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 warnings_state_stack.append(current_state);
225 }
226 else
227 {
228 592 main_warnings_state = current_state;
229 }
230 610 }
231
232 606 void pull_warnings(bool warnings_command)
233 {
234
4/4
✓ Branch 0 taken 594 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 588 times.
✓ Branch 3 taken 6 times.
606 if (warnings_state_stack.count > 0 || !warnings_command)
235 {
236 300 warnings_state prev_state;
237
238
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 294 times.
306 if (warnings_command)
239 {
240
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 prev_state = warnings_state_stack[warnings_state_stack.count - 1];
241 }
242 else
243 {
244 588 prev_state = main_warnings_state;
245 }
246
247
2/2
✓ Branch 0 taken 19200 times.
✓ Branch 1 taken 600 times.
19800 for (int i = 0; i < (int)warning_id_count; ++i)
248 {
249 19200 asar_warnings[i].enabled = prev_state.enabled[i];
250 }
251
252
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 588 times.
600 if (warnings_command)
253 {
254 12 warnings_state_stack.remove(warnings_state_stack.count - 1);
255 }
256 300 }
257 else
258 {
259 6 asar_throw_error(0, error_type_block, error_id_pullwarnings_without_pushwarnings);
260 }
261 600 }
262
263 588 void verify_warnings()
264 {
265
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 582 times.
588 if (warnings_state_stack.count > 0)
266 {
267 6 asar_throw_error(0, error_type_null, error_id_pushwarnings_without_pullwarnings);
268
269 6 warnings_state_stack.reset();
270 }
271 588 }
272