2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
31 ** Massachusetts Institute of Technology
34 # include "splintMacros.nf"
36 # include "llgrammar.h"
37 # include "checking.h"
41 static /*@only@*/ cstring
printBadArgs (sortSetList p_args
);
42 static /*@only@*/ sortSet
43 standardOperators (/*@null@*/ nameNode p_n
, sortSetList p_argSorts
, sort p_q
);
44 static bool isStandardOperator (/*@null@*/ nameNode p_n
);
45 static void assignSorts (termNode p_t
, sort p_s
);
48 computePossibleSorts (/*@returned@*/ /*@null@*/ termNode t
)
52 if (t
!= (termNode
) 0)
61 case TRM_UNCHANGEDALL
:
62 case TRM_UNCHANGEDOTHERS
:
68 sortSetList argSorts
= sortSetList_new ();
72 if (termNodeList_size (t
->args
) != 0)
74 termNodeList_elements (t
->args
, arg
)
76 (void) computePossibleSorts (arg
);
78 if (sortSet_size (arg
->possibleSorts
) == 0)
84 sortSetList_addh (argSorts
, arg
->possibleSorts
);
86 } end_termNodeList_elements
;
90 lslOpSet_free (t
->possibleOps
);
91 sortSetList_free (argSorts
);
92 t
->possibleOps
= lslOpSet_new ();
97 ops
= symtable_opsWithLegalDomain (g_symtab
, t
->name
, argSorts
, t
->given
);
98 lslOpSet_free (t
->possibleOps
);
101 lslOpSet_elements (t
->possibleOps
, op
)
104 sort
= sigNode_rangeSort (op
->signature
);
105 (void) sortSet_insert (t
->possibleSorts
, sort
);
106 } end_lslOpSet_elements
;
108 standards
= standardOperators (t
->name
, argSorts
, t
->given
);
110 sortSet_elements (standards
, el
)
112 (void) sortSet_insert (t
->possibleSorts
, el
);
113 } end_sortSet_elements
;
115 sortSet_free (standards
);
117 if (!(t
->error_reported
) && sortSet_size (t
->possibleSorts
) == 0)
119 unsigned int arity
= termNodeList_size (t
->args
);
120 errtok
= nameNode_errorToken (t
->name
);
122 /* errorShowPoint (inputStream_thisLine (lclsource), ltoken_getCol (errtok)); */
124 if (isStandardOperator (t
->name
))
127 message ("Type error: %q not declared for %q",
128 nameNode_unparse (t
->name
), printBadArgs (argSorts
)));
130 else if (t
->name
!= NULL
131 && symtable_opExistsWithArity (g_symtab
, t
->name
, arity
))
133 sigNodeSet possibleOps
= symtable_possibleOps (g_symtab
, t
->name
);
134 cstring opName
= nameNode_unparse (t
->name
);
137 ** all these will be standardOperators soon...
140 if (cstring_equalLit (opName
, "__ [__]"))
143 message ("Type error: %q not declared for %q",
144 opName
, printBadArgs (argSorts
)));
149 message ("Type error: %q declared: %q\ngiven: %q",
151 sigNodeSet_unparseSomeSigs (possibleOps
),
152 printBadArgs (argSorts
)));
157 sigNodeSet possibleOps
;
160 llassert (t
->name
!= NULL
);
162 possibleOps
= symtable_possibleOps (g_symtab
, t
->name
);
163 npossibleOps
= sigNodeSet_size (possibleOps
);
166 ** evs --- check is it is wrong arity...
169 if (npossibleOps
== 0)
173 message ("Undeclared operator: %q", nameNode_unparse (t
->name
)));
179 message ("Operator %q declared for %q arguments, given %d",
180 nameNode_unparse (t
->name
),
181 sigNodeSet_unparsePossibleAritys (possibleOps
),
185 t
->error_reported
= TRUE
;
187 sortSetList_free (argSorts
);
196 static /*@only@*/ cstring
197 printBadArgs (sortSetList args
)
199 if (sortSetList_size (args
) == 1)
201 return (sortSet_unparseOr (sortSetList_head (args
)));
205 cstring s
= cstring_undefined
;
208 sortSetList_elements (args
, ss
)
211 s
= message ("arg %d: %q", argno
, sortSet_unparseOr (ss
));
213 s
= message ("%q; arg %d: %q", s
, argno
, sortSet_unparseOr (ss
));
215 } end_sortSetList_elements
;
222 checkSort (/*@returned@*/ termNode t
)
229 (void) computePossibleSorts (t
);
230 sorts
= t
->possibleSorts
;
232 llassert (sortSet_isDefined (sorts
));
234 size
= sortSet_size (sorts
);
237 case 0: /* complain later */
239 case 1: /* just right */
240 theSort
= sortSet_choose (sorts
);
241 assignSorts (t
, theSort
);
244 /* we allow C literals to have multiple sorts */
245 if (t
->kind
!= TRM_LITERAL
)
247 errtok
= termNode_errorToken (t
);
248 t
->error_reported
= TRUE
;
251 message ("Term %q: can have more than one possible type. Possible types: %q",
252 termNode_unparse (t
), sortSet_unparseClean (sorts
)));
259 assignSorts (termNode t
, sort s
)
261 /* other kinds are already assigned bottom-up */
266 case TRM_ZEROARY
: /* pick s to be the sort chosen */
268 sortSet_elements (t
->possibleSorts
, s2
)
270 if (sort_equal (s2
, s
))
272 sortSet_free (t
->possibleSorts
);
273 t
->possibleSorts
= sortSet_new ();
274 (void) sortSet_insert (t
->possibleSorts
, s
);
278 } end_sortSet_elements
;
280 case TRM_APPLICATION
:
282 lslOpSet sigs
= t
->possibleOps
;
283 lslOpSet oldops
= lslOpSet_undefined
;
284 sigNode op
= (sigNode
) 0;
285 nameNode name
= t
->name
;
286 termNodeList args
= t
->args
;
289 errtok
= nameNode_errorToken (name
);
291 /* why compute again? to check for duplicates */
292 lslOpSet_elements (sigs
, sig
)
294 sort rsort
= sigNode_rangeSort (sig
->signature
);
296 if (sort_equal (s
, rsort
))
302 t
->error_reported
= TRUE
;
305 message ("Ambiguous operator %q: %q or %q",
306 nameNode_unparse (name
),
307 sigNode_unparse (op
),
308 sigNode_unparse (sig
->signature
)));
312 iop
= (lslOp
) dmalloc (sizeof (*iop
));
316 oldops
= t
->possibleOps
;
317 t
->possibleOps
= lslOpSet_new ();
318 iop
->name
= nameNode_copy (name
);
320 (void) lslOpSet_insert (t
->possibleOps
, iop
);
325 } end_lslOpSet_elements
;
327 lslOpSet_free (oldops
);
331 if (sortSet_size (t
->possibleSorts
) == 1)
333 t
->sort
= sortSet_choose (t
->possibleSorts
);
337 /* errorShowPoint (inputStream_thisLine (lclsource), ltoken_getCol (errtok)); */
338 t
->error_reported
= TRUE
;
340 lclerror (errtok
, message ("Operator not found: %q",
341 nameNode_unparse (name
)));
347 if (termNodeList_empty (args
))
349 if (op
!= (sigNode
) 0)
351 /* was --- NB: copy to avoid interference */
352 /* shouldn't need to copy --- its a fresh list */
353 sortList dom
= sigNode_domain (op
);
355 sortList_reset (dom
);
356 termNodeList_elements (args
, arg
)
358 assignSorts (arg
, sortList_current (dom
));
359 sortList_advance (dom
);
360 } end_termNodeList_elements
;
366 errtok
= nameNode_errorToken (name
);
367 /* errorShowPoint (inputStream_thisLine (lclsource), ltoken_getCol (errtok)); */
368 t
->error_reported
= TRUE
;
370 lclerror (errtok
, message ("No matching operator: %q",
371 nameNode_unparse (name
)));
377 default: /* do nothing */
383 checkLclPredicate (ltoken t
, lclPredicateNode n
)
387 if ((n
== NULL
) || (n
->predicate
== NULL
))
389 llcontbuglit ("checkLclPredicate expects valid lclPredicate. "
390 "Skipping current check");
394 /* check only if there are no previous errors */
396 if (!n
->predicate
->error_reported
)
398 /* check that the sort of n is boolean */
399 theSort
= n
->predicate
->sort
;
400 if (!sort_compatible (theSort
, g_sortCapBool
))
402 if (sort_isNoSort (theSort
))
404 ; /* "Expects a boolean term. Given term has unknown sort" */
408 cstring clauset
= ltoken_getRawString (t
);
410 if (cstring_firstChar (clauset
) == '(')
412 clauset
= cstring_makeLiteral ("Equality");
416 /* uppercase first letter */
417 clauset
= cstring_copy (clauset
);
418 cstring_setChar (clauset
, 1,
419 (char) toupper (cstring_firstChar (clauset
)));
422 lclerror (t
, message ("%q expects a boolean term, given %q.",
423 clauset
, sort_unparse (theSort
)));
431 ** these should not be doing string comparisons!
434 static bool isDeRefOperator (cstring s
)
436 return (cstring_equalLit (s
, "*"));
439 static bool isStateOperator (cstring s
)
441 return (cstring_equalLit (s
, "^") ||
442 cstring_equalLit (s
, "'") ||
443 cstring_equalLit (s
, "\\any") ||
444 cstring_equalLit (s
, "\\pre") ||
445 cstring_equalLit (s
, "\\post"));
448 static bool isCompareOperator (cstring s
) /* YUCK!!! */
450 return (cstring_equalLit (s
, "\\eq") ||
451 cstring_equalLit (s
, "\\neq") ||
452 cstring_equalLit (s
, "=") ||
453 cstring_equalLit (s
, "!=") ||
454 cstring_equalLit (s
, "~=") ||
455 cstring_equalLit (s
, "=="));
458 static bool isStandardOperator (/*@null@*/ nameNode n
)
460 if (n
!= (nameNode
) 0)
464 opFormNode opf
= n
->content
.opform
;
466 llassert (opf
!= NULL
);
470 case OPF_IF
: return TRUE
;
475 cstring s
= ltoken_getRawString (opf
->content
.anyop
);
477 if (isStateOperator (s
)) return TRUE
;
483 cstring s
= ltoken_getRawString (opf
->content
.anyop
);
485 return (isDeRefOperator (s
));
489 cstring s
= ltoken_getRawString (opf
->content
.anyop
);
491 return (isCompareOperator (s
));
523 int code
= ltoken_getCode (n
->content
.opid
);
525 if (code
== simpleId
)
527 cstring text
= nameNode_unparse (n
);
528 bool ret
= (cstring_equalLit (text
, "trashed")
529 || cstring_equalLit (text
, "maxIndex")
530 || cstring_equalLit (text
, "minIndex")
531 || cstring_equalLit (text
, "isSub"));
537 return (code
== LLT_MODIFIES
|| code
== LLT_FRESH
538 || code
== LLT_UNCHANGED
|| code
== LLT_SIZEOF
);
544 static /*@only@*/ sortSet
545 standardOperators (/*@null@*/ nameNode n
, sortSetList argSorts
, /*@unused@*/ sort q
)
548 sortSet ret
= sortSet_new ();
550 if (n
== (nameNode
) 0) return ret
;
554 int code
= ltoken_getCode (n
->content
.opid
);
556 if (sortSetList_size (argSorts
) == 1)
558 sortSetList_reset (argSorts
);
560 argSet
= sortSetList_current (argSorts
);
562 sortSet_elements (argSet
, current
)
566 sn
= sort_quietLookup (current
);
568 while (sn
->kind
== SRT_SYN
)
570 sn
= sort_quietLookup (sn
->baseSort
);
573 /*@-loopswitchbreak@*/
578 cstring text
= ltoken_getRawString (n
->content
.opid
);
580 if (cstring_equalLit (text
, "trashed")) /* GACK! */
582 if (sn
->kind
== SRT_OBJ
||
583 sn
->kind
== SRT_ARRAY
)
584 (void) sortSet_insert (ret
, g_sortBool
);
587 if (cstring_equalLit (text
, "maxIndex") ||
588 cstring_equalLit (text
, "minIndex"))
590 if (sn
->kind
== SRT_ARRAY
|| sn
->kind
== SRT_PTR
)
591 (void) sortSet_insert (ret
, g_sortInt
);
593 /* if (lsymbol_fromChars ("maxIndex") */
600 if (sn
->kind
== SRT_OBJ
||
601 sn
->kind
== SRT_ARRAY
)
603 (void) sortSet_insert (ret
, g_sortBool
);
607 if (sn
->kind
== SRT_OBJ
||
608 sn
->kind
== SRT_ARRAY
||
609 sn
->kind
== SRT_VECTOR
)
610 (void) sortSet_insert (ret
, g_sortInt
);
615 } end_sortSet_elements
;
620 opFormNode opf
= n
->content
.opform
;
622 llassert (opf
!= NULL
);
628 ** if __ then __ else __ : bool, S, S -> S
629 ** is defined for all sorts
632 if (sortSetList_size (argSorts
) == 3)
634 argSet
= sortSetList_head (argSorts
);
636 if (sortSet_member (argSet
, g_sortBool
))
638 sortSetList_reset (argSorts
);
639 sortSetList_advance (argSorts
);
641 argSet
= sortSetList_current (argSorts
);
643 if (sortSet_size (argSet
) == 1)
645 sort clause
= sortSet_choose (argSet
);
648 sortSetList_advance (argSorts
);
649 argSet
= sortSetList_current (argSorts
);
651 clause2
= sortSet_choose (argSet
);
653 if (sortSet_size (argSet
) == 1 &&
654 sort_equal (clause
, clause2
))
656 (void) sortSet_insert (ret
, clause
);
664 cstring s
= ltoken_getRawString (opf
->content
.anyop
);
666 if (isStateOperator (s
))
668 if (sortSetList_size (argSorts
) == 1)
670 sortSetList_reset (argSorts
);
672 argSet
= sortSetList_current (argSorts
);
674 sortSet_elements (argSet
, current
)
678 sn
= sort_quietLookup (current
);
680 while (sn
->kind
== SRT_SYN
)
682 sn
= sort_quietLookup (sn
->baseSort
);
688 (void) sortSet_insert (ret
, sn
->baseSort
);
691 (void) sortSet_insert (ret
,
692 sort_makeVec (ltoken_undefined
, current
));
695 (void) sortSet_insert (ret
,
696 sort_makeTuple (ltoken_undefined
, current
));
699 (void) sortSet_insert (ret
,
700 sort_makeUnionVal (ltoken_undefined
, current
));
714 llbuglit ("standardOperators: Synonym in switch");
716 } end_sortSet_elements
;
724 cstring s
= ltoken_getRawString (opf
->content
.anyop
);
726 if (isDeRefOperator (s
))
728 if (sortSetList_size (argSorts
) == 1)
730 sortSetList_reset (argSorts
);
732 argSet
= sortSetList_current (argSorts
);
734 sortSet_elements (argSet
, current
)
738 sn
= sort_quietLookup (current
);
740 while (sn
->kind
== SRT_SYN
)
742 sn
= sort_quietLookup (sn
->baseSort
);
745 if (sn
->kind
== SRT_PTR
)
747 (void) sortSet_insert (ret
, sn
->baseSort
);
749 } end_sortSet_elements
;
758 cstring s
= ltoken_getRawString (opf
->content
.anyop
);
760 if (isCompareOperator (s
))
762 if (sortSetList_size (argSorts
) == 2)
766 sortSetList_reset (argSorts
);
768 argSet
= sortSetList_current (argSorts
);
769 sortSetList_advance (argSorts
);
770 argSet2
= sortSetList_current (argSorts
);
772 if (sortSet_size (argSet
) == 1)
774 sortSet_elements (argSet
, cl
)
776 sortSet_elements (argSet2
, cl2
)
778 if (sort_equal (cl
, cl2
))
780 (void) sortSet_insert (ret
, g_sortBool
);
782 } end_sortSet_elements
;
783 } end_sortSet_elements
;
816 /*@=loopswitchbreak@*/