]> andersk Git - splint.git/blame - src/checking.c
Committing after merging Evan's changes.
[splint.git] / src / checking.c
CommitLineData
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** checking.c
26**
27** sort checking.
28**
29** AUTHOR:
30** Yang Meng Tan,
31** Massachusetts Institute of Technology
32*/
33
1b8ae690 34# include "splintMacros.nf"
616915dd 35# include "llbasic.h"
36# include "llgrammar.h"
37# include "checking.h"
38# include "lclscan.h"
39
40/*@+ignorequals@*/
41
42static /*@only@*/ cstring printBadArgs (sortSetList p_args);
43static /*@only@*/ sortSet
53306cab 44 standardOperators (/*@null@*/ nameNode p_n, sortSetList p_argSorts, sort p_q);
616915dd 45static bool isStandardOperator (/*@null@*/ nameNode p_n);
46static void assignSorts (termNode p_t, sort p_s);
47
48/*@null@*/ termNode
49computePossibleSorts (/*@returned@*/ /*@null@*/ termNode t)
50{
51 ltoken errtok;
52
53 if (t != (termNode) 0)
54 {
55 switch (t->kind)
56 {
57 case TRM_LITERAL:
58 case TRM_CONST:
59 case TRM_VAR:
60 case TRM_ZEROARY:
61 case TRM_SIZEOF:
62 case TRM_UNCHANGEDALL:
63 case TRM_UNCHANGEDOTHERS:
64 case TRM_QUANTIFIER:
65 break;
66 case TRM_APPLICATION:
67 {
68 bool fail = FALSE;
69 sortSetList argSorts = sortSetList_new ();
70 lslOpSet ops;
71 sortSet standards;
72
73 if (termNodeList_size (t->args) != 0)
74 {
75 termNodeList_elements (t->args, arg)
76 {
77 (void) computePossibleSorts (arg);
78
79 if (sortSet_size (arg->possibleSorts) == 0)
80 {
81 fail = TRUE;
82 }
83 else
84 {
85 sortSetList_addh (argSorts, arg->possibleSorts);
86 }
87 } end_termNodeList_elements;
88
89 if (fail)
90 {
91 lslOpSet_free (t->possibleOps);
92 sortSetList_free (argSorts);
93 t->possibleOps = lslOpSet_new ();
94 return t;
95 }
96 }
97
98 ops = symtable_opsWithLegalDomain (g_symtab, t->name, argSorts, t->given);
99 lslOpSet_free (t->possibleOps);
100 t->possibleOps = ops;
101
102 lslOpSet_elements (t->possibleOps, op)
103 {
104 sort sort;
105 sort = sigNode_rangeSort (op->signature);
106 (void) sortSet_insert (t->possibleSorts, sort);
107 } end_lslOpSet_elements;
108
109 standards = standardOperators (t->name, argSorts, t->given);
110
111 sortSet_elements (standards, el)
112 {
113 (void) sortSet_insert (t->possibleSorts, el);
114 } end_sortSet_elements;
115
116 sortSet_free (standards);
117
118 if (!(t->error_reported) && sortSet_size (t->possibleSorts) == 0)
119 {
120 unsigned int arity = termNodeList_size (t->args);
121 errtok = nameNode_errorToken (t->name);
122
28bf4b0b 123 /* errorShowPoint (inputStream_thisLine (lclsource), ltoken_getCol (errtok)); */
616915dd 124
125 if (isStandardOperator (t->name))
126 {
127 lclerror (errtok,
128 message ("Type error: %q not declared for %q",
129 nameNode_unparse (t->name), printBadArgs (argSorts)));
130 }
131 else if (t->name != NULL
132 && symtable_opExistsWithArity (g_symtab, t->name, arity))
133 {
134 sigNodeSet possibleOps = symtable_possibleOps (g_symtab, t->name);
135 cstring opName = nameNode_unparse (t->name);
136
137 /*
138 ** all these will be standardOperators soon...
139 */
140
141 if (cstring_equalLit (opName, "__ [__]"))
142 {
143 lclerror (errtok,
144 message ("Type error: %q not declared for %q",
145 opName, printBadArgs (argSorts)));
146 }
147 else
148 {
149 lclerror (errtok,
150 message ("Type error: %q declared: %q\ngiven: %q",
151 opName,
152 sigNodeSet_unparseSomeSigs (possibleOps),
153 printBadArgs (argSorts)));
154 }
155 }
156 else
157 {
158 sigNodeSet possibleOps;
159 int npossibleOps;
160
161 llassert (t->name != NULL);
162
163 possibleOps = symtable_possibleOps (g_symtab, t->name);
164 npossibleOps = sigNodeSet_size (possibleOps);
165
166 /*
167 ** evs --- check is it is wrong arity...
168 */
169
170 if (npossibleOps == 0)
171 {
172 lclerror
173 (errtok,
174 message ("Undeclared operator: %q", nameNode_unparse (t->name)));
175 }
176 else
177 {
178 lclerror
179 (errtok,
180 message ("Operator %q declared for %q arguments, given %d",
181 nameNode_unparse (t->name),
182 sigNodeSet_unparsePossibleAritys (possibleOps),
183 arity));
184 }
185 }
186 t->error_reported = TRUE;
187 }
188 sortSetList_free (argSorts);
189 break;
190 }
191 }
192 }
193
194 return t;
195}
196
197static /*@only@*/ cstring
198printBadArgs (sortSetList args)
199{
200 if (sortSetList_size (args) == 1)
201 {
202 return (sortSet_unparseOr (sortSetList_head (args)));
203 }
204 else
205 {
206 cstring s = cstring_undefined;
207 int argno = 1;
208
209 sortSetList_elements (args, ss)
210 {
211 if (argno == 1)
212 s = message ("arg %d: %q", argno, sortSet_unparseOr (ss));
213 else
214 s = message ("%q; arg %d: %q", s, argno, sortSet_unparseOr (ss));
215 argno++;
216 } end_sortSetList_elements;
217
218 return s;
219 }
220}
221
222termNode
223checkSort (/*@returned@*/ termNode t)
224{
225 sortSet sorts;
226 sort theSort;
227 int size;
228 ltoken errtok;
229
230 (void) computePossibleSorts (t);
231 sorts = t->possibleSorts;
232
233 llassert (sortSet_isDefined (sorts));
234
235 size = sortSet_size (sorts);
236 switch (size)
237 {
238 case 0: /* complain later */
239 break;
240 case 1: /* just right */
241 theSort = sortSet_choose (sorts);
242 assignSorts (t, theSort);
243 break;
244 default:
245 /* we allow C literals to have multiple sorts */
246 if (t->kind != TRM_LITERAL)
247 {
248 errtok = termNode_errorToken (t);
249 t->error_reported = TRUE;
250
251 lclerror (errtok,
252 message ("Term %q: can have more than one possible type. Possible types: %q",
253 termNode_unparse (t), sortSet_unparseClean (sorts)));
254 }
255 }
256 return t;
257}
258
259static void
260 assignSorts (termNode t, sort s)
261{
262 /* other kinds are already assigned bottom-up */
263 ltoken errtok;
264
265 switch (t->kind)
266 {
267 case TRM_ZEROARY: /* pick s to be the sort chosen */
268 case TRM_LITERAL:
269 sortSet_elements (t->possibleSorts, s2)
270 {
28bf4b0b 271 if (sort_equal (s2, s))
616915dd 272 {
273 sortSet_free (t->possibleSorts);
274 t->possibleSorts = sortSet_new ();
275 (void) sortSet_insert (t->possibleSorts, s);
276 t->sort = s;
277 }
278 return;
279 } end_sortSet_elements;
280 break;
281 case TRM_APPLICATION:
282 {
283 lslOpSet sigs = t->possibleOps;
284 lslOpSet oldops = lslOpSet_undefined;
285 sigNode op = (sigNode) 0;
286 nameNode name = t->name;
287 termNodeList args = t->args;
288 bool found = FALSE;
289
290 errtok = nameNode_errorToken (name);
291
292 /* why compute again? to check for duplicates */
293 lslOpSet_elements (sigs, sig)
294 {
295 sort rsort = sigNode_rangeSort (sig->signature);
296
28bf4b0b 297 if (sort_equal (s, rsort))
616915dd 298 {
299 lslOp iop;
300
301 if (found)
302 {
303 t->error_reported = TRUE;
304
305 lclerror (errtok,
306 message ("Ambiguous operator %q: %q or %q",
307 nameNode_unparse (name),
308 sigNode_unparse (op),
309 sigNode_unparse (sig->signature)));
310 return;
311 }
312
313 iop = (lslOp) dmalloc (sizeof (*iop));
314 found = TRUE;
315 op = sig->signature;
316
317 oldops = t->possibleOps;
318 t->possibleOps = lslOpSet_new ();
319 iop->name = nameNode_copy (name);
320 iop->signature = op;
321 (void) lslOpSet_insert (t->possibleOps, iop);
322 t->sort = s;
323 /*@-branchstate@*/
324 }
325 /*@=branchstate@*/
326 } end_lslOpSet_elements;
327
328 lslOpSet_free (oldops);
329
330 if (!found)
331 {
332 if (sortSet_size (t->possibleSorts) == 1)
333 {
334 t->sort = sortSet_choose (t->possibleSorts);
335 }
336 else
337 {
28bf4b0b 338 /* errorShowPoint (inputStream_thisLine (lclsource), ltoken_getCol (errtok)); */
616915dd 339 t->error_reported = TRUE;
340
341 lclerror (errtok, message ("Operator not found: %q",
342 nameNode_unparse (name)));
343 /* evs --- ??? */
344 }
345 return;
346 }
347
348 if (termNodeList_empty (args))
349 {
350 if (op != (sigNode) 0)
351 {
352 /* was --- NB: copy to avoid interference */
353 /* shouldn't need to copy --- its a fresh list */
354 sortList dom = sigNode_domain (op);
355
356 sortList_reset (dom);
357 termNodeList_elements (args, arg)
358 {
359 assignSorts (arg, sortList_current (dom));
360 sortList_advance (dom);
361 } end_termNodeList_elements;
362
363 sortList_free (dom);
364 }
365 else
366 {
367 errtok = nameNode_errorToken (name);
28bf4b0b 368 /* errorShowPoint (inputStream_thisLine (lclsource), ltoken_getCol (errtok)); */
616915dd 369 t->error_reported = TRUE;
370
371 lclerror (errtok, message ("No matching operator: %q",
372 nameNode_unparse (name)));
373 }
374 return;
375 }
376 break;
377 }
378 default: /* do nothing */
379 break;
380 }
381}
382
383void
384checkLclPredicate (ltoken t, lclPredicateNode n)
385{
386 sort theSort;
387
388 if ((n == NULL) || (n->predicate == NULL))
389 {
390 llcontbuglit ("checkLclPredicate expects valid lclPredicate. "
391 "Skipping current check");
392 return;
393 }
394
395 /* check only if there are no previous errors */
396
397 if (!n->predicate->error_reported)
398 {
399 /* check that the sort of n is boolean */
400 theSort = n->predicate->sort;
2a6e9c30 401 if (!sort_compatible (theSort, g_sortCapBool))
616915dd 402 {
403 if (sort_isNoSort (theSort))
404 {
405 ; /* "Expects a boolean term. Given term has unknown sort" */
406 }
407 else
408 {
409 cstring clauset = ltoken_getRawString (t);
410
411 if (cstring_firstChar (clauset) == '(')
412 {
413 clauset = cstring_makeLiteral ("Equality");
414 }
415 else
416 {
417 /* uppercase first letter */
418 clauset = cstring_copy (clauset);
419 cstring_setChar (clauset, 1,
420 (char) toupper (cstring_firstChar (clauset)));
421 }
422
423 lclerror (t, message ("%q expects a boolean term, given %q.",
424 clauset, sort_unparse (theSort)));
425
426 }
427 }
428 }
429}
430
431/*
432** these should not be doing string comparisons!
433*/
434
435static bool isDeRefOperator (cstring s)
436{
437 return (cstring_equalLit (s, "*"));
438}
439
440static bool isStateOperator (cstring s)
441{
442 return (cstring_equalLit (s, "^") ||
443 cstring_equalLit (s, "'") ||
444 cstring_equalLit (s, "\\any") ||
445 cstring_equalLit (s, "\\pre") ||
446 cstring_equalLit (s, "\\post"));
447}
448
449static bool isCompareOperator (cstring s) /* YUCK!!! */
450{
451 return (cstring_equalLit (s, "\\eq") ||
452 cstring_equalLit (s, "\\neq") ||
453 cstring_equalLit (s, "=") ||
454 cstring_equalLit (s, "!=") ||
455 cstring_equalLit (s, "~=") ||
456 cstring_equalLit (s, "=="));
457}
458
459static bool isStandardOperator (/*@null@*/ nameNode n)
460{
461 if (n != (nameNode) 0)
462 {
463 if (!n->isOpId)
464 {
465 opFormNode opf = n->content.opform;
466
467 llassert (opf != NULL);
468
469 switch (opf->kind)
470 {
471 case OPF_IF: return TRUE;
472 case OPF_ANYOP:
473 break;
474 case OPF_MANYOP:
475 {
476 cstring s = ltoken_getRawString (opf->content.anyop);
477
478 if (isStateOperator (s)) return TRUE;
479 return FALSE;
480 }
481 case OPF_ANYOPM:
482 /* operator: *__ */
483 {
484 cstring s = ltoken_getRawString (opf->content.anyop);
485
486 return (isDeRefOperator (s));
487 }
488 case OPF_MANYOPM:
489 {
490 cstring s = ltoken_getRawString (opf->content.anyop);
491
492 return (isCompareOperator (s));
493 }
494 case OPF_MIDDLE:
495 break;
496 case OPF_MMIDDLE:
497 break;
498 case OPF_MIDDLEM:
499 break;
500 case OPF_MMIDDLEM:
501 break;
502 case OPF_BMIDDLE:
503 break;
504 case OPF_BMMIDDLE:
505 break;
506 case OPF_BMIDDLEM:
507 break;
508 case OPF_BMMIDDLEM:
509 break;
510 case OPF_SELECT:
511 break;
512 case OPF_MAP:
513 break;
514 case OPF_MSELECT:
515 break;
516 case OPF_MMAP:
517 break;
518 default:
519 break;
520 }
521 }
522 else
523 {
524 int code = ltoken_getCode (n->content.opid);
525
526 if (code == simpleId)
527 {
528 cstring text = nameNode_unparse (n);
529 bool ret = (cstring_equalLit (text, "trashed")
530 || cstring_equalLit (text, "maxIndex")
531 || cstring_equalLit (text, "minIndex")
532 || cstring_equalLit (text, "isSub"));
533
534 cstring_free (text);
535 return ret;
536 }
537
538 return (code == LLT_MODIFIES || code == LLT_FRESH
539 || code == LLT_UNCHANGED || code == LLT_SIZEOF);
540 }
541 }
542 return FALSE;
543}
544
545static /*@only@*/ sortSet
53306cab 546standardOperators (/*@null@*/ nameNode n, sortSetList argSorts, /*@unused@*/ sort q)
616915dd 547{
548 sortSet argSet;
549 sortSet ret = sortSet_new ();
550
551 if (n == (nameNode) 0) return ret;
552
553 if (n->isOpId)
554 {
555 int code = ltoken_getCode (n->content.opid);
556
557 if (sortSetList_size (argSorts) == 1)
558 {
559 sortSetList_reset (argSorts);
560
561 argSet = sortSetList_current (argSorts);
562
563 sortSet_elements (argSet, current)
564 {
565 sortNode sn;
566
567 sn = sort_quietLookup (current);
568
28bf4b0b 569 while (sn->kind == SRT_SYN)
616915dd 570 {
28bf4b0b 571 sn = sort_quietLookup (sn->baseSort);
616915dd 572 }
573
574 /*@-loopswitchbreak@*/
575 switch (code)
576 {
577 case simpleId:
578 {
579 cstring text = ltoken_getRawString (n->content.opid);
580
581 if (cstring_equalLit (text, "trashed")) /* GACK! */
582 {
28bf4b0b 583 if (sn->kind == SRT_OBJ ||
584 sn->kind == SRT_ARRAY)
2a6e9c30 585 (void) sortSet_insert (ret, g_sortBool);
616915dd 586 }
587
588 if (cstring_equalLit (text, "maxIndex") ||
589 cstring_equalLit (text, "minIndex"))
590 {
28bf4b0b 591 if (sn->kind == SRT_ARRAY || sn->kind == SRT_PTR)
2a6e9c30 592 (void) sortSet_insert (ret, g_sortInt);
616915dd 593
594 /* if (lsymbol_fromChars ("maxIndex") */
595 }
596 }
597 break;
598 case LLT_MODIFIES:
599 case LLT_FRESH:
600 case LLT_UNCHANGED:
28bf4b0b 601 if (sn->kind == SRT_OBJ ||
602 sn->kind == SRT_ARRAY)
616915dd 603 {
2a6e9c30 604 (void) sortSet_insert (ret, g_sortBool);
616915dd 605 }
606 break;
607 case LLT_SIZEOF:
28bf4b0b 608 if (sn->kind == SRT_OBJ ||
609 sn->kind == SRT_ARRAY ||
610 sn->kind == SRT_VECTOR)
2a6e9c30 611 (void) sortSet_insert (ret, g_sortInt);
616915dd 612 break;
613 default:
614 break;
615 }
616 } end_sortSet_elements;
617 }
618 }
619 else
620 {
621 opFormNode opf = n->content.opform;
622
623 llassert (opf != NULL);
624
625 switch (opf->kind)
626 {
627 case OPF_IF:
628 /*
629 ** if __ then __ else __ : bool, S, S -> S
630 ** is defined for all sorts
631 */
632
633 if (sortSetList_size (argSorts) == 3)
634 {
635 argSet = sortSetList_head (argSorts);
636
2a6e9c30 637 if (sortSet_member (argSet, g_sortBool))
616915dd 638 {
639 sortSetList_reset (argSorts);
640 sortSetList_advance (argSorts);
641
642 argSet = sortSetList_current (argSorts);
643
644 if (sortSet_size (argSet) == 1)
645 {
646 sort clause = sortSet_choose (argSet);
647 sort clause2;
648
649 sortSetList_advance (argSorts);
650 argSet = sortSetList_current (argSorts);
651
652 clause2 = sortSet_choose (argSet);
653
654 if (sortSet_size (argSet) == 1 &&
28bf4b0b 655 sort_equal (clause, clause2))
616915dd 656 {
657 (void) sortSet_insert (ret, clause);
658 }
659 }
660 }
661 }
662 break;
663 case OPF_MANYOP:
664 {
665 cstring s = ltoken_getRawString (opf->content.anyop);
666
667 if (isStateOperator (s))
668 {
669 if (sortSetList_size (argSorts) == 1)
670 {
671 sortSetList_reset (argSorts);
672
673 argSet = sortSetList_current (argSorts);
674
675 sortSet_elements (argSet, current)
676 {
677 sortNode sn;
678
679 sn = sort_quietLookup (current);
680
28bf4b0b 681 while (sn->kind == SRT_SYN)
616915dd 682 {
28bf4b0b 683 sn = sort_quietLookup (sn->baseSort);
616915dd 684 }
685
28bf4b0b 686 switch (sn->kind)
616915dd 687 {
688 case SRT_OBJ:
28bf4b0b 689 (void) sortSet_insert (ret, sn->baseSort);
616915dd 690 break;
691 case SRT_ARRAY:
692 (void) sortSet_insert (ret,
693 sort_makeVec (ltoken_undefined, current));
694 break;
695 case SRT_STRUCT:
696 (void) sortSet_insert (ret,
697 sort_makeTuple (ltoken_undefined, current));
698 break;
699 case SRT_UNION:
700 (void) sortSet_insert (ret,
701 sort_makeUnionVal (ltoken_undefined, current));
702 break;
703 case SRT_TUPLE:
704 case SRT_UNIONVAL:
705 case SRT_ENUM:
706 case SRT_LAST:
707 case SRT_FIRST:
708 case SRT_NONE:
709 case SRT_HOF:
710 case SRT_PRIM:
711 case SRT_PTR:
712 case SRT_VECTOR:
713 break;
714 case SRT_SYN:
715 llbuglit ("standardOperators: Synonym in switch");
716 }
717 } end_sortSet_elements ;
718 }
719 }
720 }
721 break;
722 case OPF_ANYOPM:
723 /* operator: *__ */
724 {
725 cstring s = ltoken_getRawString (opf->content.anyop);
726
727 if (isDeRefOperator (s))
728 {
729 if (sortSetList_size (argSorts) == 1)
730 {
731 sortSetList_reset (argSorts);
732
733 argSet = sortSetList_current (argSorts);
734
735 sortSet_elements (argSet, current)
736 {
737 sortNode sn;
738
739 sn = sort_quietLookup (current);
740
28bf4b0b 741 while (sn->kind == SRT_SYN)
616915dd 742 {
28bf4b0b 743 sn = sort_quietLookup (sn->baseSort);
616915dd 744 }
745
28bf4b0b 746 if (sn->kind == SRT_PTR)
616915dd 747 {
28bf4b0b 748 (void) sortSet_insert (ret, sn->baseSort);
616915dd 749 }
750 } end_sortSet_elements;
751 }
752 }
753 }
754 break;
755 case OPF_ANYOP:
756 break;
757 case OPF_MANYOPM:
758 {
759 cstring s = ltoken_getRawString (opf->content.anyop);
760
761 if (isCompareOperator (s))
762 {
763 if (sortSetList_size (argSorts) == 2)
764 {
765 sortSet argSet2;
766
767 sortSetList_reset (argSorts);
768
769 argSet = sortSetList_current (argSorts);
770 sortSetList_advance (argSorts);
771 argSet2 = sortSetList_current (argSorts);
772
773 if (sortSet_size (argSet) == 1)
774 {
775 sortSet_elements (argSet, cl)
776 {
777 sortSet_elements (argSet2, cl2)
778 {
28bf4b0b 779 if (sort_equal (cl, cl2))
616915dd 780 {
2a6e9c30 781 (void) sortSet_insert (ret, g_sortBool);
616915dd 782 }
783 } end_sortSet_elements;
784 } end_sortSet_elements;
785 }
786 }
787 }
788 }
789 break;
790 case OPF_MIDDLE:
791 break;
792 case OPF_MMIDDLE:
793 break;
794 case OPF_MIDDLEM:
795 break;
796 case OPF_MMIDDLEM:
797 break;
798 case OPF_BMIDDLE:
799 break;
800 case OPF_BMMIDDLE:
801 break;
802 case OPF_BMIDDLEM:
803 break;
804 case OPF_BMMIDDLEM:
805 break;
806 case OPF_SELECT:
807 break;
808 case OPF_MAP:
809 break;
810 case OPF_MSELECT:
811 break;
812 case OPF_MMAP:
813 break;
814 default:
815 break;
816 }
817 /*@=loopswitchbreak@*/
818 }
819 return ret;
820}
This page took 0.166623 seconds and 5 git commands to generate.