]>
Commit | Line | Data |
---|---|---|
616915dd | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
c59f5181 | 3 | ** Copyright (C) 1994-2003 University of Virginia, |
616915dd | 4 | ** Massachusetts Institute of Technology |
5 | ** | |
6 | ** This program is free software; you can redistribute it and/or modify it | |
7 | ** under the terms of the GNU General Public License as published by the | |
8 | ** Free Software Foundation; either version 2 of the License, or (at your | |
9 | ** option) any later version. | |
10 | ** | |
11 | ** This program is distributed in the hope that it will be useful, but | |
12 | ** WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | ** General Public License for more details. | |
15 | ** | |
16 | ** The GNU General Public License is available from http://www.gnu.org/ or | |
17 | ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
18 | ** MA 02111-1307, USA. | |
19 | ** | |
155af98d | 20 | ** For information on splint: info@splint.org |
21 | ** To report a bug: splint-bug@splint.org | |
11db3170 | 22 | ** For more information: http://www.splint.org |
616915dd | 23 | */ |
24 | /* | |
25 | ** flagMarkerList.c | |
26 | ** | |
27 | ** based on list_template.c | |
28 | ** | |
29 | ** where T has T_equal (or change this) and T_unparse | |
30 | ** | |
31 | ** invariant: flagMarker's are listed in order | |
32 | */ | |
33 | ||
1b8ae690 | 34 | # include "splintMacros.nf" |
616915dd | 35 | # include "basic.h" |
36 | ||
60eced23 | 37 | static int flagMarkerList_lastBeforeLoc (flagMarkerList p_s, fileloc p_loc) /*@*/ ; |
38 | ||
abd7f895 | 39 | static bool |
40 | flagMarkerList_contains (flagMarkerList p_s, flagMarker p_fm) /*@*/ ; | |
41 | ||
616915dd | 42 | flagMarkerList |
43 | flagMarkerList_new () | |
44 | { | |
45 | flagMarkerList s = (flagMarkerList) dmalloc (sizeof (*s)); | |
46 | ||
47 | s->nelements = 0; | |
48 | s->nspace = flagMarkerListBASESIZE; | |
49 | s->elements = (flagMarker *) | |
50 | dmalloc (sizeof (*s->elements) * flagMarkerListBASESIZE); | |
51 | ||
52 | return (s); | |
53 | } | |
54 | ||
55 | static void | |
56 | flagMarkerList_grow (flagMarkerList s) | |
57 | { | |
58 | int i; | |
59 | flagMarker *newelements; | |
60 | ||
61 | s->nspace += flagMarkerListBASESIZE; | |
62 | ||
63 | newelements = (flagMarker *) dmalloc (sizeof (*newelements) | |
64 | * (s->nelements + s->nspace)); | |
65 | ||
66 | for (i = 0; i < s->nelements; i++) | |
67 | { | |
68 | newelements[i] = s->elements[i]; | |
69 | } | |
70 | ||
71 | sfree (s->elements); | |
72 | s->elements = newelements; | |
73 | } | |
74 | ||
abd7f895 | 75 | bool flagMarkerList_add (flagMarkerList s, flagMarker fm) |
616915dd | 76 | { |
77 | int i = s->nelements - 1; | |
60eced23 | 78 | int lastloc; |
79 | ||
abd7f895 | 80 | DPRINTF (("Add: %s", flagMarker_unparse (fm))); |
81 | ||
82 | if (flagMarkerList_contains (s, fm)) | |
83 | { | |
84 | flagMarker_free (fm); | |
85 | DPRINTF (("List contains: %s", flagMarkerList_unparse (s))); | |
86 | return FALSE; | |
87 | } | |
616915dd | 88 | |
616915dd | 89 | if (i > 0) |
90 | { | |
91 | flagMarker last = s->elements[i]; | |
92 | ||
616915dd | 93 | if (flagMarker_isIgnoreCount (last)) |
94 | { | |
95 | if (!flagMarker_isIgnoreOff (fm)) | |
96 | { | |
97 | if (flagMarker_isLocalSet (fm)) | |
98 | { | |
28bf4b0b | 99 | if (llforceerror |
100 | (FLG_WARNFLAGS, | |
101 | cstring_makeLiteral ("Cannot set flag inside ignore " | |
102 | "count region."), | |
103 | flagMarker_getLoc (fm))) | |
104 | { | |
105 | llgenindentmsg | |
106 | (cstring_makeLiteral ("Ignore count region starts"), | |
107 | flagMarker_getLoc (last)); | |
108 | } | |
616915dd | 109 | } |
110 | else | |
111 | { | |
112 | if (flagMarker_isIgnoreOn (fm)) | |
113 | { | |
28bf4b0b | 114 | if (llforceerror |
115 | (FLG_WARNFLAGS, | |
116 | cstring_makeLiteral ("Cannot nest ignore regions."), | |
117 | flagMarker_getLoc (fm))) | |
118 | { | |
119 | llgenindentmsg | |
120 | (cstring_makeLiteral ("Previous ignore region starts"), | |
121 | flagMarker_getLoc (last)); | |
122 | } | |
616915dd | 123 | } |
124 | } | |
125 | ||
126 | flagMarker_free (fm); | |
abd7f895 | 127 | return FALSE; |
616915dd | 128 | } |
129 | } | |
130 | else | |
131 | { | |
132 | if (flagMarker_isIgnoreOff (last)) | |
133 | { | |
134 | flagMarker nlast = s->elements [i - 1]; | |
28bf4b0b | 135 | |
616915dd | 136 | if (flagMarker_isIgnoreCount (nlast)) |
137 | { | |
28bf4b0b | 138 | if (fileloc_sameFileAndLine (flagMarker_getLoc (fm), |
139 | flagMarker_getLoc (nlast))) | |
616915dd | 140 | { |
141 | if (flagMarker_isLocalSet (fm)) | |
142 | { | |
28bf4b0b | 143 | if (llforceerror |
144 | (FLG_WARNFLAGS, | |
abd7f895 | 145 | cstring_makeLiteral |
146 | ("Cannot set flag inside ignore " | |
147 | "count region."), | |
28bf4b0b | 148 | flagMarker_getLoc (fm))) |
149 | { | |
150 | llgenindentmsg | |
abd7f895 | 151 | (cstring_makeLiteral |
152 | ("Ignore count region starts"), | |
28bf4b0b | 153 | flagMarker_getLoc (nlast)); |
154 | DPRINTF (("Last: %s / %s", | |
155 | fileloc_unparse (flagMarker_getLoc (last)), | |
156 | fileloc_unparse (flagMarker_getLoc (fm)))); | |
157 | ||
158 | } | |
616915dd | 159 | } |
160 | else | |
161 | { | |
162 | if (flagMarker_isIgnoreOn (fm)) | |
163 | { | |
28bf4b0b | 164 | if (llforceerror |
165 | (FLG_WARNFLAGS, | |
166 | cstring_makeLiteral ("Cannot nest ignore regions."), | |
167 | flagMarker_getLoc (fm))) | |
168 | { | |
169 | llgenindentmsg | |
170 | (cstring_makeLiteral ("Previous ignore region starts"), | |
171 | flagMarker_getLoc (nlast)); | |
172 | } | |
616915dd | 173 | } |
174 | } | |
175 | ||
176 | flagMarker_free (fm); | |
abd7f895 | 177 | return FALSE; |
616915dd | 178 | } |
179 | } | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
616915dd | 184 | |
185 | /* | |
60eced23 | 186 | ** Need to insert this flag in the right place (after the last before loc flag) |
616915dd | 187 | */ |
188 | ||
60eced23 | 189 | lastloc = flagMarkerList_lastBeforeLoc (s, flagMarker_getLoc (fm)); |
616915dd | 190 | |
191 | if (s->nspace <= 0) | |
192 | { | |
193 | flagMarkerList_grow (s); | |
194 | } | |
195 | ||
196 | s->nspace--; | |
60eced23 | 197 | |
198 | if (lastloc == -1) | |
199 | { | |
200 | /* Add it to the end of the list */ | |
201 | s->elements[s->nelements] = fm; | |
202 | } | |
203 | else | |
204 | { | |
205 | DPRINTF (("Inserting: %s in %s", | |
206 | flagMarker_unparse (fm), | |
207 | flagMarkerList_unparse (s))); | |
208 | ||
209 | /* Insert it at location lastloc + 1, push other flags down */ | |
210 | for (i = s->nelements; i > lastloc + 1; i--) | |
211 | { | |
212 | s->elements [i] = s->elements [i - 1]; | |
213 | } | |
214 | ||
215 | s->elements [lastloc + 1] = fm; | |
216 | ||
217 | } | |
218 | ||
616915dd | 219 | s->nelements++; |
abd7f895 | 220 | return TRUE; |
60eced23 | 221 | } |
616915dd | 222 | |
223 | void flagMarkerList_checkSuppressCounts (flagMarkerList s) | |
224 | { | |
225 | int nexpected = 0; | |
226 | int nsuppressed = 0; | |
227 | fileloc loc = fileloc_undefined; | |
228 | bool inCount = FALSE; | |
229 | int i; | |
616915dd | 230 | |
231 | for (i = 0; i < s->nelements; i++) | |
232 | { | |
233 | flagMarker current = s->elements[i]; | |
ccf0a4a8 | 234 | DPRINTF (("flagMarker: %s / %s", |
235 | flagMarker_unparse (current), | |
236 | bool_unparse (inCount))); | |
abd7f895 | 237 | |
616915dd | 238 | if (flagMarker_isIgnoreCount (current)) |
239 | { | |
240 | llassert (!inCount); | |
241 | inCount = TRUE; | |
242 | nexpected = flagMarker_getCount (current); | |
243 | loc = flagMarker_getLoc (current); | |
244 | nsuppressed = 0; | |
ccf0a4a8 | 245 | } |
616915dd | 246 | else if (flagMarker_isIgnoreOff (current)) |
247 | { | |
248 | if (inCount) | |
249 | { | |
250 | inCount = FALSE; | |
251 | llassert (fileloc_isDefined (loc)); | |
252 | ||
253 | if (nexpected > 0 && nexpected != nsuppressed) | |
254 | { | |
28bf4b0b | 255 | /* Must use forceerror to prevent self-suppression! */ |
256 | llforceerror | |
616915dd | 257 | (FLG_SUPCOUNTS, |
258 | message | |
28bf4b0b | 259 | ("Line expects to suppress %d error%&, found %d error%&", |
616915dd | 260 | nexpected, nsuppressed), |
261 | loc); | |
262 | } | |
263 | } | |
264 | } | |
265 | else if (flagMarker_isSuppress (current)) | |
266 | { | |
267 | nsuppressed++; | |
268 | } | |
269 | else | |
270 | { | |
271 | ; | |
272 | } | |
273 | } | |
274 | ||
275 | llassert (!inCount); | |
276 | } | |
277 | ||
278 | static void flagMarkerList_splice (flagMarkerList s, | |
279 | int index, | |
280 | /*@keep@*/ flagMarker fm) | |
281 | { | |
282 | fileloc loc = flagMarker_getLoc (fm); | |
283 | fileloc beforeloc, afterloc; | |
284 | int i; | |
285 | ||
286 | llassert (index >= 0 && (index + 1 < s->nelements)); | |
287 | ||
288 | beforeloc = flagMarker_getLoc (s->elements[index]); | |
289 | afterloc = flagMarker_getLoc (s->elements[index + 1]);; | |
290 | ||
291 | llassert (fileloc_sameFile (beforeloc, loc)); | |
292 | llassert (fileloc_sameFile (afterloc, loc)); | |
293 | ||
294 | if (s->nspace <= 0) | |
295 | { | |
296 | flagMarkerList_grow (s); | |
297 | } | |
298 | ||
299 | for (i = s->nelements; i > index + 1; i--) | |
300 | { | |
301 | s->elements[i] = s->elements[i - 1]; | |
302 | } | |
303 | ||
304 | s->elements[index + 1] = fm; | |
305 | s->nelements++; | |
306 | s->nspace--; | |
307 | ||
308 | } | |
309 | ||
310 | /*@only@*/ cstring | |
311 | flagMarkerList_unparse (flagMarkerList s) | |
312 | { | |
313 | int i; | |
314 | cstring st = cstring_makeLiteral ("["); | |
315 | ||
316 | for (i = 0; i < s->nelements; i++) | |
317 | { | |
318 | if (i == 0) | |
319 | { | |
320 | st = message ("%q %q", st, flagMarker_unparse (s->elements[i])); | |
321 | } | |
322 | else | |
323 | st = message ("%q, %q", st, flagMarker_unparse (s->elements[i])); | |
324 | } | |
325 | ||
326 | st = message ("%q ]", st); | |
327 | return st; | |
328 | } | |
329 | ||
330 | void | |
331 | flagMarkerList_free (flagMarkerList s) | |
332 | { | |
333 | int i; | |
334 | for (i = 0; i < s->nelements; i++) | |
335 | { | |
336 | flagMarker_free (s->elements[i]); | |
337 | } | |
338 | ||
339 | sfree (s->elements); | |
340 | sfree (s); | |
341 | } | |
342 | ||
616915dd | 343 | static int |
344 | flagMarkerList_lastBeforeLoc (flagMarkerList s, fileloc loc) | |
345 | { | |
346 | int i; | |
347 | ||
348 | for (i = s->nelements - 1; i >= 0; i--) | |
349 | { | |
350 | flagMarker current = s->elements[i]; | |
351 | ||
352 | if (fileloc_sameFile (current->loc, loc) | |
353 | && (!flagMarker_beforeMarker (current, loc))) | |
354 | { | |
355 | return i; | |
356 | } | |
616915dd | 357 | } |
358 | ||
359 | return -1; | |
360 | } | |
abd7f895 | 361 | |
362 | static bool | |
363 | flagMarkerList_contains (flagMarkerList s, flagMarker fm) | |
364 | { | |
365 | int i; | |
366 | ||
367 | for (i = s->nelements - 1; i >= 0; i--) | |
368 | { | |
369 | flagMarker current = s->elements[i]; | |
370 | ||
371 | if (flagMarker_equal (current, fm)) | |
372 | { | |
373 | return TRUE; | |
374 | } | |
375 | } | |
376 | ||
377 | return FALSE; | |
378 | } | |
379 | ||
380 | /* | |
381 | ** returns YES iff | |
382 | ** > in ignore region (there is an ignore ON marker not followed by OFF) | |
383 | ** > code is OFF (-) | |
384 | ** | |
385 | ** returns NO iff | |
386 | ** > not in ignore region | |
387 | ** > code is ON (+) | |
388 | ** | |
389 | ** returns MAYBE iff | |
390 | ** > not in ignore region | |
391 | ** > code is unset or = | |
392 | ** | |
393 | ** requires: invariant for flagMarkerList: | |
394 | ** flagMarker's are sorted by line and col | |
395 | */ | |
616915dd | 396 | |
397 | ynm | |
398 | flagMarkerList_suppressError (flagMarkerList s, flagcode code, fileloc loc) | |
399 | { | |
400 | int i; | |
401 | bool ignoreOff = FALSE; | |
402 | bool nameChecksOff = FALSE; | |
403 | bool flagOff = FALSE; | |
404 | ynm flagSet = MAYBE; | |
405 | bool islib = FALSE; | |
406 | bool isNameChecksFlag = flagcode_isNameChecksFlag (code); | |
407 | ||
408 | if (fileloc_isLib (loc)) | |
409 | { | |
410 | i = s->nelements - 1; | |
411 | islib = TRUE; | |
412 | } | |
413 | else | |
414 | { | |
415 | i = flagMarkerList_lastBeforeLoc (s, loc); | |
416 | } | |
616915dd | 417 | |
418 | if (i < 0) | |
419 | { | |
60eced23 | 420 | DPRINTF (("RETURNING!")); |
616915dd | 421 | return MAYBE; |
422 | } | |
423 | ||
424 | /* | |
425 | ** Go backwards through the remaining flagMarkers in this file. | |
426 | */ | |
427 | ||
428 | for (; i >= 0; i--) | |
429 | { | |
430 | flagMarker current = s->elements[i]; | |
616915dd | 431 | |
60eced23 | 432 | DPRINTF (("Check current: %s", flagMarker_unparse (current))); |
433 | ||
616915dd | 434 | if (!islib && !flagMarker_sameFile (current, loc)) |
435 | { | |
60eced23 | 436 | DPRINTF (("Not same file: %s", fileloc_unparse (loc))); |
616915dd | 437 | break; |
438 | } | |
439 | ||
440 | if (flagMarker_isIgnoreOff (current)) | |
441 | { | |
442 | ignoreOff = TRUE; | |
443 | } | |
444 | else if (flagMarker_isIgnoreOn (current)) | |
445 | { | |
446 | if (!ignoreOff) | |
447 | { | |
448 | return YES; | |
449 | } | |
450 | } | |
451 | else if (flagMarker_isIgnoreCount (current)) | |
452 | { | |
453 | if (!ignoreOff) | |
454 | { | |
455 | flagMarkerList_splice (s, i, | |
456 | flagMarker_createSuppress (code, loc)); | |
457 | return YES; | |
458 | } | |
459 | } | |
460 | else if (flagMarker_isLocalSet (current)) | |
461 | { | |
462 | ||
463 | if (!flagOff && flagMarker_getCode (current) == code) | |
464 | { | |
465 | ynm set = flagMarker_getSet (current); | |
466 | ||
467 | if (ynm_isOff (set)) | |
468 | { | |
469 | return YES; | |
470 | } | |
471 | else | |
472 | { | |
473 | if (ynm_isOn (set)) | |
474 | { | |
475 | flagOff = TRUE; | |
476 | flagSet = NO; | |
477 | } | |
478 | else | |
479 | { | |
60eced23 | 480 | flagOff = TRUE; |
616915dd | 481 | flagSet = MAYBE; |
482 | } | |
483 | ||
484 | if (ignoreOff) | |
485 | { | |
486 | if (isNameChecksFlag && !nameChecksOff) | |
487 | { | |
488 | ; | |
489 | } | |
490 | else | |
491 | { | |
492 | return flagSet; | |
493 | } | |
494 | } | |
495 | } | |
496 | } | |
497 | ||
498 | if (flagMarker_getCode (current) == FLG_NAMECHECKS | |
499 | && !nameChecksOff && isNameChecksFlag) | |
500 | { | |
501 | ynm set = flagMarker_getSet (current); | |
502 | ||
503 | if (ynm_isOff (set)) | |
504 | { | |
505 | return YES; | |
506 | } | |
507 | else | |
508 | { | |
509 | if (ynm_isOn (set)) | |
510 | { | |
511 | nameChecksOff = TRUE; | |
512 | flagSet = NO; | |
513 | } | |
514 | else | |
515 | { | |
60eced23 | 516 | nameChecksOff = TRUE; |
616915dd | 517 | flagSet = MAYBE; |
518 | } | |
519 | ||
520 | if (ignoreOff && flagOff) | |
521 | { | |
522 | return flagSet; | |
523 | } | |
524 | } | |
525 | } | |
526 | } | |
527 | else | |
528 | { | |
529 | llassert (flagMarker_isSuppress (current)); | |
530 | } | |
531 | } | |
532 | ||
533 | return flagSet; | |
534 | } | |
535 | ||
536 | bool | |
537 | flagMarkerList_inIgnore (flagMarkerList s, fileloc loc) | |
538 | { | |
539 | int i; | |
540 | ||
541 | if (fileloc_isLib (loc)) | |
542 | { | |
543 | return FALSE; | |
544 | } | |
545 | ||
546 | i = flagMarkerList_lastBeforeLoc (s, loc); | |
547 | ||
548 | /* | |
549 | ** Go backwards through the remaining flagMarkers in this file. | |
550 | */ | |
551 | ||
552 | for (; i >= 0; i--) | |
553 | { | |
554 | flagMarker current = s->elements[i]; | |
555 | ||
556 | if (!flagMarker_sameFile (current, loc)) | |
557 | { | |
558 | break; | |
559 | } | |
560 | ||
561 | if (flagMarker_isIgnoreOff (current)) | |
562 | { | |
563 | return FALSE;; | |
564 | } | |
565 | else if (flagMarker_isIgnoreOn (current)) | |
566 | { | |
567 | return TRUE; | |
568 | } | |
569 | else if (flagMarker_isIgnoreCount (current)) | |
570 | { | |
571 | flagMarkerList_splice (s, i, | |
572 | flagMarker_createSuppress (SKIP_FLAG, loc)); | |
573 | return TRUE; | |
574 | } | |
575 | else | |
576 | { | |
577 | llassert (flagMarker_isLocalSet (current) | |
578 | || flagMarker_isSuppress (current)); | |
579 | } | |
580 | } | |
581 | ||
582 | return FALSE; | |
583 | } | |
584 |