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
25 ** usymtab_interface.c
27 ** Grammar interface to symtab.
29 ** The Splint parser will build symbol tables for abstract types and
30 ** function declarations.
34 # include "splintMacros.nf"
36 # include "llgrammar.h"
37 # include "usymtab_interface.h"
38 # include "structNames.h"
41 declareFcnAux (fcnNode p_f
, /*@only@*/ qtype p_qt
, ctype p_ct
, typeId p_tn
,
42 bool p_priv
, bool p_spec
);
44 static uentryList
paramNodeList_toUentryList (paramNodeList p_p
);
45 static /*@observer@*/ cstring
getVarName (/*@null@*/ typeExpr p_x
);
46 static qtype
convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode p_n
);
47 static ctype
convertTypeExpr (ctype p_c
, /*@null@*/ typeExpr p_x
);
48 static /*@exposed@*/ sRef
fixTermNode (termNode p_n
, fcnNode p_f
, uentryList p_cl
);
49 static sRefSet
fixModifies (fcnNode p_f
, uentryList p_cl
);
52 convertuentryList (stDeclNodeList x
)
54 uentryList fl
= uentryList_new ();
57 stDeclNodeList_elements (x
, i
)
59 declaratorNodeList d
= i
->declarators
;
60 qtype q
= convertLclTypeSpecNode (i
->lcltypespec
);
62 declaratorNodeList_elements (d
, j
)
66 qtype_setType (q
, convertTypeExpr (qtype_getType (q
), j
->type
));
67 id
= idDecl_create (cstring_copy (getVarName (j
->type
)), qtype_copy (q
));
68 fl
= uentryList_add (fl
, uentry_makeIdVariable (id
));
70 } end_declaratorNodeList_elements
;
73 } end_stDeclNodeList_elements
;
81 convert_uentryList (paramNodeList x
)
83 uentryList p
= uentryList_undefined
;
84 bool first_one
= TRUE
;
87 paramNodeList_elements (x
, i
)
89 if (i
!= (paramNode
) 0)
91 if (paramNode_isElipsis (i
))
94 p
= uentryList_add (p
, uentry_makeElipsisMarker ());
98 qtype q
= convertLclTypeSpecNode (i
->type
);
99 typeExpr t
= i
->paramdecl
;
101 qtype_setType (q
, convertTypeExpr (qtype_getType (q
), t
));
103 /* note: has to be like this to hack around void ???? still */
107 if (ctype_isVoid (qtype_getType (q
)))
109 llassert (uentryList_isUndefined (p
));
118 ** don't do qualifiers here, will get errors later
121 p
= uentryList_add (p
, uentry_makeUnnamedVariable (qtype_getType (q
)));
127 llbug (cstring_makeLiteral ("convertuentryList: null paramNode"));
129 } end_paramNodeList_elements
;
133 llassert (uentryList_isUndefined (p
));
135 p
= uentryList_makeMissingParams ();
145 ** modify c with pointer, array, function
147 ** (based on printTypeExpr2 from abstract.c)
152 convertTypeExpr (ctype c
, typeExpr x
)
154 if (x
== (typeExpr
) 0)
164 return (convertTypeExpr (ctype_makePointer (c
), x
->content
.pointer
));
166 return (convertTypeExpr (ctype_makeArray (c
), x
->content
.array
.elementtype
));
169 ctype rv
= convertTypeExpr (c
, x
->content
.function
.returntype
);
170 uentryList p
= paramNodeList_toUentryList (x
->content
.function
.args
);
172 if (x
->content
.function
.returntype
!= NULL
173 && x
->content
.function
.returntype
->wrapped
== 1
174 && ctype_isPointer (rv
))
176 rv
= ctype_baseArrayPtr (rv
);
179 return (ctype_makeParamsFunction (rv
, p
));
183 llfatalbug (message ("convertTypeExpr: unknown typeExprKind: %d",
193 ctype
convertCTypeExpr (ctype c
, typeExpr x
)
195 if (x
== (typeExpr
) 0)
202 case TEXPR_BASE
: return (c
);
203 case TEXPR_PTR
: return (convertCTypeExpr (ctype_makePointer (c
),
204 x
->content
.pointer
));
205 case TEXPR_ARRAY
: return (convertCTypeExpr (ctype_makeArray (c
),
206 x
->content
.array
.elementtype
));
209 ctype rv
= convertCTypeExpr (c
, x
->content
.function
.returntype
);
210 uentryList p
= convert_uentryList (x
->content
.function
.args
);
212 return (ctype_makeParamsFunction (rv
, p
));
216 llfatalbug (message ("convertCTypeExpr: unknown typeExprKind: %d", (int) x
->kind
));
224 ** convertLclTypeSpecNode
226 ** LclTypeSpecNode --> ctype
227 ** this is the base type only!
233 ** for now, assume only last leaf is relevant.
234 ** this should be a safe assumption in general???
238 convertLeaves (ltokenList f
)
240 ctype c
= ctype_unknown
;
242 ltokenList_reset (f
);
244 ltokenList_elements (f
, current
)
246 switch (ltoken_getCode (current
))
248 case LLT_TYPEDEF_NAME
:
250 cstring tn
= ltoken_getRawString (current
);
252 if (usymtab_existsTypeEither (tn
))
254 c
= ctype_combine (uentry_getAbstractType
255 (usymtab_lookupEither (tn
)), c
);
257 else if (cstring_equalLit (tn
, "bool"))
260 ** Bogus...keep consistent with old lcl builtin.
266 fileloc loc
= fileloc_fromTok (current
);
268 voptgenerror (FLG_UNRECOG
,
269 message ("Unrecognized type: %s", tn
), loc
);
274 (tn
, ctype_unknown
, MAYBE
, qual_createConcrete (),
275 fileloc_getBuiltin ()));
278 /*@switchbreak@*/ break;
281 c
= ctype_combine (ctype_char
, c
);
282 /*@switchbreak@*/ break;
285 c
= ctype_combine (ctype_double
, c
);
286 /*@switchbreak@*/ break;
288 c
= ctype_combine (ctype_float
, c
);
289 /*@switchbreak@*/ break;
292 /*@switchbreak@*/ break;
294 c
= ctype_combine (ctype_int
, c
);
295 /*@switchbreak@*/ break;
297 c
= ctype_combine (c
, ctype_lint
);
298 /*@switchbreak@*/ break;
300 c
= ctype_combine (c
, ctype_sint
);
301 /*@switchbreak@*/ break;
303 c
= ctype_combine (c
, ctype_int
);
304 /*@switchbreak@*/ break;
306 c
= ctype_combine (c
, ctype_uint
);
307 /*@switchbreak@*/ break;
309 c
= ctype_combine (ctype_unknown
, c
);
310 /*@switchbreak@*/ break;
312 c
= ctype_combine (ctype_void
, c
);
313 /*@switchbreak@*/ break;
315 llcontbug (cstring_makeLiteral ("convertLeaves: enum"));
317 /*@switchbreak@*/ break;
319 llfatalbug (message ("convertLeaves: bad token: %q",
320 ltoken_unparseCodeName (current
)));
322 } end_ltokenList_elements
;
328 convertEnumList (ltokenList enums
)
330 enumNameList el
= enumNameList_new ();
332 if (ltokenList_isDefined (enums
))
334 ltokenList_elements (enums
, i
)
337 (el
, enumName_create (cstring_copy (ltoken_unparse (i
))));
338 } end_ltokenList_elements
;
344 static /*@only@*/ qtype
345 convertLclTypeSpecNode (/*@null@*/ lclTypeSpecNode n
)
348 if (n
!= (lclTypeSpecNode
) 0)
356 qtype c1
= convertLclTypeSpecNode (n
->content
.conj
->a
);
357 qtype c2
= convertLclTypeSpecNode (n
->content
.conj
->b
);
363 if (fileloc_isLib (g_currentloc
)
364 || fileloc_isStandardLibrary (g_currentloc
))
366 result
= qtype_mergeImplicitAlt (c1
, c2
);
370 result
= qtype_mergeAlt (c1
, c2
);
376 llassert (n
->content
.type
!= NULL
);
377 result
= qtype_create (convertLeaves (n
->content
.type
->ctypes
));
379 case LTS_STRUCTUNION
:
382 cstring cn
= cstring_undefined
;
384 sn
= n
->content
.structorunion
;
386 llassert (sn
!= (strOrUnionNode
) 0);
388 if (!ltoken_isUndefined (sn
->opttagid
))
390 cn
= cstring_copy (ltoken_getRawString (sn
->opttagid
));
400 if (usymtab_existsStructTag (cn
))
403 result
= qtype_create (uentry_getAbstractType
404 (usymtab_lookupStructTag (cn
)));
409 uentryList fl
= convertuentryList (sn
->structdecls
);
412 ct
= ctype_createStruct (cstring_copy (cn
), fl
);
415 ** If it was a forward declaration, this could add it to
416 ** the table. Need to check if it exists again...
419 if (usymtab_existsStructTag (cn
))
421 result
= qtype_create (uentry_getAbstractType
422 (usymtab_lookupStructTag (cn
)));
426 fileloc loc
= fileloc_fromTok (n
->content
.structorunion
->tok
);
427 uentry ue
= uentry_makeStructTag (cn
, ct
, loc
);
429 result
= qtype_create (usymtab_supTypeEntry (ue
));
434 /*@switchbreak@*/ break;
436 if (usymtab_existsUnionTag (cn
))
439 result
= qtype_create (uentry_getAbstractType
440 (usymtab_lookupUnionTag (cn
)));
448 fl
= convertuentryList (sn
->structdecls
);
449 ct
= ctype_createUnion (cstring_copy (cn
), fl
);
452 ** If it was a forward declaration, this could add it to
453 ** the table. Need to check if it exists again...
458 if (usymtab_existsUnionTag (cn
))
461 result
= qtype_create (uentry_getAbstractType
462 (usymtab_lookupUnionTag (cn
)));
466 fileloc loc
= fileloc_fromTok (n
->content
.structorunion
->tok
);
467 uentry ue
= uentry_makeUnionTag (cn
, ct
, loc
);
469 result
= qtype_create (usymtab_supTypeEntry (ue
));
474 /*@switchbreak@*/ break;
481 enumSpecNode e
= n
->content
.enumspec
;
488 llassert (e
!= NULL
);
489 el
= convertEnumList (e
->enums
);
491 if (!ltoken_isUndefined (e
->opttagid
)) /* named enumerator */
493 ename
= cstring_copy (ltoken_getRawString (e
->opttagid
));
500 cet
= ctype_createEnum (ename
, el
);
502 if (usymtab_existsEnumTag (ename
))
504 ta
= uentry_getAbstractType (usymtab_lookupEnumTag (ename
));
508 fileloc loc
= fileloc_fromTok (e
->tok
);
509 uentry ue
= uentry_makeEnumTag (ename
, cet
, loc
);
511 ta
= usymtab_supTypeEntry (ue
);
514 enumNameList_elements (el
, en
)
521 ltokenList_reset (e
->enums
);
526 ltokenList_advance (e
->enums
);
529 loc
= fileloc_fromTok (ltokenList_current (e
->enums
));
530 ue
= uentry_makeSpecEnumConstant (en
, cet
, loc
);
533 ** Can't check name here, might not have
534 ** type yet. Will check in .lh file?
537 ue
= usymtab_supGlobalEntryReturn (ue
);
539 if (context_inLCLLib ())
541 uentry_setDefined (ue
, loc
);
543 } end_enumNameList_elements
;
545 result
= qtype_create (ta
);
550 llfatalbug (message ("convertLclTypeSpecNode: unknown lclTypeSpec kind: %d",
555 result
= qtype_addQualList (result
, n
->quals
);
557 if (pointers_isDefined (n
->pointers
))
559 qtype_adjustPointers (n
->pointers
, result
);
566 llcontbug (cstring_makeLiteral ("convertLclTypeSpecNode: null"));
567 return qtype_unknown ();
572 static /*@only@*/ multiVal
573 literalValue (ctype ct
, ltoken lit
)
575 cstring text
= cstring_fromChars (lsymbol_toChars (ltoken_getText (lit
)));
578 if (cstring_length (text
) > 0)
580 first
= cstring_firstChar (text
);
584 return multiVal_unknown ();
588 if /*@-usedef@*/ (first
== '\"') /*@=usedef@*/
590 size_t len
= cstring_length (text
) - 2;
591 char *val
= mstring_create (len
);
593 llassert (cstring_lastChar (text
) == '\"');
594 strncpy (val
, cstring_toCharsSafe (text
) + 1, len
);
595 return (multiVal_makeString (cstring_fromCharsO (val
)));
598 if (ctype_isDirectInt (ct
) || ctype_isPointer (ct
))
602 if (sscanf (cstring_toCharsSafe (text
), "%ld", &val
) == 1)
604 return multiVal_makeInt (val
);
608 return multiVal_unknown ();
615 ** unfortunately, because the abstract types are different, this
616 ** cannot be easily subsumed into declareVar.
620 doDeclareConstant (constDeclarationNode c
, bool priv
)
626 if (c
== (constDeclarationNode
) 0)
632 qt
= convertLclTypeSpecNode (t
);
634 ctx
= qtype_getType (qt
);
636 initDeclNodeList_elements (c
->decls
, i
)
638 ctype ct
= convertTypeExpr (ctx
, i
->declarator
->type
);
639 cstring s
= getVarName (i
->declarator
->type
);
641 if (ctype_isFunction (ct
))
643 fcnNode fcn
= fcnNode_fromDeclarator (lclTypeSpecNode_copy (t
),
644 declaratorNode_copy (i
->declarator
));
646 /* FALSE == unspecified function, only a declaration */
648 doDeclareFcn (fcn
, typeId_invalid
, priv
, FALSE
);
654 fileloc loc
= fileloc_fromTok (i
->declarator
->id
);
656 if (i
->value
!= (termNode
)0 &&
657 i
->value
->kind
== TRM_LITERAL
)
659 ue
= uentry_makeConstantValue (s
, ct
, loc
, priv
, literalValue (ct
, i
->value
->literal
));
663 ue
= uentry_makeConstantValue (s
, ct
, loc
, priv
, multiVal_unknown ());
666 uentry_reflectQualifiers (ue
, qtype_getQuals (qt
));
668 if (context_inLCLLib () && !priv
)
670 uentry_setDefined (ue
, loc
);
673 usymtab_supGlobalEntry (ue
);
675 } end_initDeclNodeList_elements
;
681 getVarName (/*@null@*/ typeExpr x
)
683 cstring s
= cstring_undefined
;
685 if (x
!= (typeExpr
) 0)
690 s
= ltoken_getRawString (x
->content
.base
);
693 s
= getVarName (x
->content
.pointer
);
696 s
= getVarName (x
->content
.array
.elementtype
);
699 s
= getVarName (x
->content
.function
.returntype
);
702 llfatalbug (message ("getVarName: unknown typeExprKind: %d", (int) x
->kind
));
710 doDeclareVar (varDeclarationNode v
, bool priv
)
715 if (v
== (varDeclarationNode
) 0)
721 c
= convertLclTypeSpecNode (t
);
723 initDeclNodeList_elements (v
->decls
, i
)
725 ctype ct
= convertTypeExpr (qtype_getType (c
), i
->declarator
->type
);
726 cstring s
= getVarName (i
->declarator
->type
);
728 qtype_setType (c
, ct
);
730 if (ctype_isFunction (ct
))
735 fcn
= fcnNode_fromDeclarator (lclTypeSpecNode_copy (t
),
736 declaratorNode_copy (i
->declarator
));
738 /* FALSE == unspecified function, only a declaration */
739 declareFcnAux (fcn
, qtype_unknown (), ct
,
740 typeId_invalid
, priv
, FALSE
);
745 fileloc loc
= fileloc_fromTok (i
->declarator
->id
);
746 uentry le
= uentry_makeVariable (s
, ct
, loc
, priv
);
748 uentry_reflectQualifiers (le
, qtype_getQuals (c
));
750 if (uentry_isCheckedUnknown (le
))
752 if (context_getFlag (FLG_IMPCHECKEDSTRICTSPECGLOBALS
))
754 uentry_setCheckedStrict (le
);
756 else if (context_getFlag (FLG_IMPCHECKEDSPECGLOBALS
))
758 uentry_setChecked (le
);
760 else if (context_getFlag (FLG_IMPCHECKMODSPECGLOBALS
))
762 uentry_setCheckMod (le
);
770 if (context_inLCLLib () && !priv
)
772 uentry_setDefined (le
, loc
);
775 if (initDeclNode_isRedeclaration (i
))
777 usymtab_replaceEntry (le
);
781 le
= usymtab_supEntrySrefReturn (le
);
784 } end_initDeclNodeList_elements
;
790 processGlob (/*@returned@*/ globSet globs
, varDeclarationNode v
)
792 if (v
== (varDeclarationNode
) 0)
799 globs
= globSet_insert (globs
, v
->sref
);
803 lclTypeSpecNode t
= v
->type
;
804 qtype qt
= convertLclTypeSpecNode (t
);
805 ctype c
= qtype_getType (qt
);
808 initDeclNodeList_elements (v
->decls
, i
)
812 qualList quals
= qtype_getQuals (qt
);
814 s
= getVarName (i
->declarator
->type
);
815 ue
= usymtab_lookupGlobSafe (s
);
817 if (uentry_isInvalid (ue
))
819 ; /* error already reported */
823 if (uentry_isPriv (ue
))
825 globs
= globSet_insert (globs
, sRef_makeSpecState ());
829 uentry ce
= uentry_copy (ue
);
830 ctype lt
= uentry_getType (ce
);
831 fileloc loc
= fileloc_fromTok (i
->declarator
->id
);
833 ct
= convertTypeExpr (c
, i
->declarator
->type
);
835 if (!ctype_match (lt
, ct
))
838 (lt
, exprNode_undefined
,
839 ct
, exprNode_undefined
,
840 message ("Global type mismatch %s (%t, %t)",
845 uentry_reflectQualifiers (ce
, quals
);
846 globs
= globSet_insert (globs
,
847 sRef_copy (uentry_getSref (ce
)));
852 } end_initDeclNodeList_elements
;
861 declareAbstractType (abstractNode n
, bool priv
)
869 if (n
== (abstractNode
) 0)
875 tn
= ltoken_getRawString (n
->name
);
877 loc
= fileloc_fromTok (n
->tok
);
879 ue
= uentry_makeDatatypeAux (tn
, ctype_unknown
,
880 ynm_fromBool (n
->isMutable
),
881 qual_createAbstract (),
886 uentry_setRefCounted (ue
);
889 if (context_inLCLLib () && !priv
)
891 uentry_setDefined (ue
, loc
);
894 uid
= usymtab_supAbstractTypeEntry (ue
, context_inLCLLib() && !priv
);
897 if (!priv
&& (ab
= n
->body
) != (abstBodyNode
) 0)
899 fcnNodeList ops
= ab
->fcns
;
901 if (!fcnNodeList_isEmpty (ops
))
903 fcnNodeList_elements (ops
, i
)
905 if (i
->typespec
== (lclTypeSpecNode
) 0)
907 cstring fname
= ltoken_getRawString (i
->name
);
909 if (usymtab_exists (fname
))
911 uentry e
= usymtab_lookup (fname
);
912 fileloc floc
= fileloc_fromTok (i
->declarator
->id
);
914 if (uentry_isForward (e
))
917 (uentry_makeTypeListFunction
918 (fname
, typeIdSet_insert (uentry_accessType (e
), uid
),
924 (uentry_makeSpecFunction
925 (fname
, uentry_getType (e
),
926 typeIdSet_insert (uentry_accessType (e
), uid
),
931 if (context_inLCLLib ())
933 llbuglit ("Jolly jeepers Wilma, it ain't dead after all!");
940 (uentry_makeForwardFunction (fname
, uid
, loc
));
947 } end_fcnNodeList_elements
;
952 static void declareExposedType (exposedNode n
, bool priv
)
958 if (n
== (exposedNode
) 0)
963 c
= convertLclTypeSpecNode (n
->type
);
965 declaratorInvNodeList_elements (n
->decls
, i
)
967 ctype realType
= convertTypeExpr (qtype_getType (c
), i
->declarator
->type
);
968 fileloc loc
= fileloc_fromTok (i
->declarator
->id
);
971 s
= getVarName (i
->declarator
->type
);
973 ue
= uentry_makeDatatypeAux (s
, realType
, MAYBE
, qual_createConcrete (),
976 uentry_reflectQualifiers (ue
, qtype_getQuals (c
));
978 if (context_inLCLLib () && !priv
)
980 uentry_setDefined (ue
, loc
);
983 (void) usymtab_supExposedTypeEntry (ue
, context_inLCLLib () && !priv
);
984 } end_declaratorInvNodeList_elements
;
990 ** ah...remember ye old days...
992 ** wow...same thing in THREE symbol tables! talk about space efficiency
993 ** (or as Joe Theory once said, its only a constant factor)
997 doDeclareType (typeNode t
, bool priv
)
1000 if (t
!= (typeNode
) 0)
1005 declareAbstractType (t
->content
.abstract
, priv
);
1009 declareExposedType (t
->content
.exposed
, priv
);
1015 llfatalbug (message ("declareType: unknown kind: %d",
1024 declareIter (iterNode iter
)
1026 fileloc loc
= fileloc_fromTok (iter
->name
);
1028 uentry_makeIter (ltoken_unparse (iter
->name
),
1031 paramNodeList_toUentryList (iter
->params
)),
1032 fileloc_copy (loc
));
1034 usymtab_supEntry (ue
);
1036 (uentry_makeEndIter (ltoken_unparse (iter
->name
), loc
));
1044 declareFcnAux (fcnNode f
, /*@only@*/ qtype qt
, ctype ct
,
1045 typeId tn
, bool priv
, bool spec
)
1049 sRefSet sl
= sRefSet_undefined
;
1050 globSet globlist
= globSet_undefined
;
1051 cstring s
= getVarName (f
->declarator
->type
);
1052 fileloc loc
= fileloc_fromTok (f
->declarator
->id
);
1056 ** type conversion generates args
1059 if (ctype_isFunction (ct
))
1061 args
= ctype_argsFunction (ct
);
1065 llcontbug (message ("Not function: %s", ctype_unparse (ct
)));
1066 args
= uentryList_undefined
;
1070 fileloc_setColumnUndefined (loc
);
1074 globals
= f
->globals
;
1076 sl
= fixModifies (f
, args
);
1079 ** Bind let declarations in modifies list
1082 varDeclarationNodeList_elements (globals
, glob
)
1084 globlist
= processGlob (globlist
, glob
);
1085 } end_varDeclarationNodeList_elements
;
1088 if (f
->checks
!= (lclPredicateNode
) 0)
1089 /* push stderr on globalList */
1090 /* modifies *stderr^ */
1094 if (!(usymtab_existsVar (cstring_makeLiteralTemp ("stderr"))))
1098 llmsglit ("Global stderr implied by checks clause, "
1099 "not declared in initializations.");
1101 tfile
= usymtab_lookupType (cstring_makeLiteralTemp ("FILE"));
1103 if (ctype_isUndefined (tfile
))
1105 llmsglit ("FILE datatype implied by checks clause not defined.");
1106 tfile
= ctype_unknown
;
1109 usymtab_supGlobalEntry
1110 (uentry_makeVariable (cstring_makeLiteralTemp ("stderr"),
1111 tfile
, fileloc_getBuiltin (), FALSE
));
1114 ue
= usymtab_lookupGlob (cstring_makeLiteralTemp ("stderr"));
1116 globlist
= globSet_insert (globlist
, sRef_copy (uentry_getSref (ue
)));
1117 sl
= sRefSet_insert (sl
, sRef_buildPointer (uentry_getSref (ue
)));
1121 if (typeId_isInvalid (tn
))
1123 acct
= context_fileAccessTypes ();
1127 acct
= typeIdSet_single (tn
);
1130 if (usymtab_exists (s
))
1132 uentry l
= usymtab_lookup (s
);
1135 if (uentry_isForward (l
) || (fileloc_isLib (uentry_whereSpecified (l
))))
1137 typeIdSet accessType
;
1139 if (uentry_isFunction (l
))
1141 accessType
= typeIdSet_union (uentry_accessType (l
),
1142 context_fileAccessTypes ());
1146 accessType
= context_fileAccessTypes ();
1151 ue
= uentry_makeSpecFunction (s
, ct
, accessType
, globlist
, sl
, loc
);
1156 globSet_free (globlist
);
1158 ue
= uentry_makeUnspecFunction (s
, ct
, accessType
, loc
);
1161 uentry_reflectQualifiers (ue
, qtype_getQuals (qt
));
1162 usymtab_supEntry (ue
);
1167 ** error reported by symtable already
1169 ** llgenerror (message ("Function redeclared: %s (previous declaration: %s)", s,
1170 ** fileloc_unparse (uentry_whereSpecified (l))),
1176 globSet_free (globlist
);
1187 le
= uentry_makePrivFunction2 (s
, ct
, acct
, globlist
, sl
, loc
);
1191 le
= uentry_makeSpecFunction (s
, ct
, acct
, globlist
, sl
, loc
);
1196 le
= uentry_makeUnspecFunction (s
, ct
, acct
, loc
);
1199 globSet_free (globlist
);
1202 if (context_inLCLLib () && !priv
)
1204 uentry_setDefined (le
, loc
);
1207 uentry_reflectQualifiers (le
, qtype_getQuals (qt
));
1209 if (qual_isUnknown (f
->special
)) {
1211 } else if (qual_isPrintfLike (f
->special
)) {
1212 uentry_setPrintfLike (le
);
1213 } else if (qual_isScanfLike (f
->special
)) {
1214 uentry_setScanfLike (le
);
1215 } else if (qual_isMessageLike (f
->special
)) {
1216 uentry_setMessageLike (le
);
1221 usymtab_supEntry (le
);
1228 doDeclareFcn (fcnNode f
, typeId tn
, bool priv
, bool spec
)
1230 qtype qt
= convertLclTypeSpecNode (f
->typespec
);
1231 ctype ct
= convertTypeExpr (qtype_getType (qt
), f
->declarator
->type
);
1233 declareFcnAux (f
, qt
, ct
, tn
, priv
, spec
);
1237 ** is s is an argument to f, return its arg no.
1238 ** otherwise, return 0
1242 getParamNo (cstring s
, fcnNode f
)
1244 /* gasp, maybe should do run-time checks here */
1245 paramNodeList params
;
1246 typeExpr fd
= f
->declarator
->type
;
1248 /* is this a bug in the LCL grammar? */
1250 while (fd
!= NULL
&& (fd
->kind
== TEXPR_PTR
|| fd
->kind
== TEXPR_ARRAY
))
1252 if (fd
->kind
== TEXPR_PTR
)
1254 fd
= fd
->content
.pointer
;
1258 /*@-null@*/ fd
= fd
->content
.array
.elementtype
; /*@=null@*/
1261 ** This is a bug in checking, that I should eventually fix.
1262 ** Need some way of deleting the guard from the true branch,
1263 ** but adding it back in the false branch...
1268 llassert (fd
!= NULL
);
1270 if (fd
->kind
!= TEXPR_FCN
)
1272 llfatalbug (message ("getParamNo: not a function: %q (%d)",
1273 typeExpr_unparse (fd
), (int) fd
->kind
));
1276 params
= fd
->content
.function
.args
;
1278 if (paramNodeList_empty (params
))
1286 paramNodeList_elements (params
, i
)
1288 if (i
->paramdecl
!= (typeExpr
) 0) /* handle (void) */
1290 if (cstring_equal (s
, getVarName (i
->paramdecl
)))
1296 } end_paramNodeList_elements
;
1301 static /*@null@*/ /*@observer@*/ termNode
1302 getLetDecl (cstring s
, fcnNode f
)
1304 letDeclNodeList x
= f
->lets
;
1306 letDeclNodeList_elements (x
, i
)
1308 if (cstring_equal (s
, ltoken_getRawString (i
->varid
)))
1310 if (i
->sortspec
!= NULL
)
1312 llbuglit ("getLetDecl: cannot return sort!");
1315 { /* is a termNode */
1319 } end_letDeclNodeList_elements
;
1321 return (termNode
) 0;
1325 ** processTermNode --- based on printTermNode2
1328 static /*@exposed@*/ sRef
1329 processTermNode (/*@null@*/ opFormNode op
, termNodeList args
,
1330 fcnNode f
, uentryList cl
)
1332 if (op
!= (opFormNode
) 0)
1337 llcontbuglit ("processTermNode: OPF_IF: not handled");
1340 llcontbuglit ("processTermNode: OPF_ANYOP: not handled");
1344 int size
= termNodeList_size (args
);
1347 && (cstring_equalLit (ltoken_getRawString (op
->content
.anyop
), "'") ||
1348 cstring_equalLit (ltoken_getRawString (op
->content
.anyop
), "^")))
1350 return (fixTermNode (termNodeList_head (args
), f
, cl
));
1360 int size
= termNodeList_size (args
);
1363 && (cstring_equalLit (ltoken_getRawString (op
->content
.anyop
), "*")))
1368 ft
= fixTermNode (termNodeList_head (args
), f
, cl
);
1369 res
= sRef_buildPointer (ft
);
1379 llcontbuglit ("OPF_MANYOPM: not handled\n");
1382 llcontbuglit ("OPF_MIDDLE: not handled\n");
1385 llcontbuglit ("OPF_MMIDDLE: not handled\n");
1388 llcontbuglit ("OPF_MIDDLEM: not handled\n");
1391 llcontbuglit ("OPF_MMIDDLEM: not handled\n");
1394 if (op
->content
.middle
== 1)
1395 llbug (message ("array fetch: [%q]",
1396 termNodeList_unparse (args
)));
1398 llcontbuglit ("OPF_BMIDDLE: bad\n");
1402 if (op
->content
.middle
<= 1)
1404 sRef arr
= fixTermNode (termNodeList_head (args
), f
, cl
);
1407 if (op
->content
.middle
== 1)
1409 termNode t
= (termNodeList_reset (args
),
1410 termNodeList_advance (args
),
1411 termNodeList_current (args
));
1413 if (t
->kind
== TRM_LITERAL
)
1418 (cstring_toCharsSafe
1419 (ltoken_getRawString (t
->literal
)),
1422 ret
= sRef_buildArrayFetchKnown (arr
, i
);
1426 ret
= sRef_buildArrayFetch (arr
);
1435 ret
= sRef_buildArrayFetch (arr
);
1441 llcontbug (message ("op->content.middle = %d",
1442 op
->content
.middle
));
1447 llcontbuglit ("OPF_BMIDDLEM not handled");
1451 llcontbuglit ("OPF_BMMIDDLEM not handled");
1455 llcontbug (message ("select: .%s",
1456 ltoken_getRawString (op
->content
.id
)));
1460 llcontbug (message ("map: .%s",
1461 ltoken_getRawString (op
->content
.id
)));
1466 sRef rec
= fixTermNode (termNodeList_head (args
), f
, cl
);
1468 ctype ct
= ctype_realType (sRef_deriveType (rec
, cl
));
1469 cstring fieldname
= ltoken_getRawString (op
->content
.id
);
1471 ct
= ctype_realType (ct
);
1474 ** does it correspond to a typedef struct field
1476 ** (kind of kludgey, but there is no direct way to
1477 ** tell if it is an lsl operator instead)
1480 if (ctype_isStructorUnion (ct
) &&
1482 (uentryList_lookupField (ctype_getFields (ct
), fieldname
)))
1484 cstring fname
= cstring_copy (fieldname
);
1486 ret
= sRef_buildField (rec
, fname
);
1487 cstring_markOwned (fname
);
1491 ret
= sRef_undefined
;
1498 sRef rec
= fixTermNode (termNodeList_head (args
), f
, cl
);
1499 sRef ret
= sRef_undefined
;
1500 ctype ct
= ctype_realType (sRef_deriveType (rec
, cl
));
1501 cstring fieldname
= ltoken_getRawString (op
->content
.id
);
1504 ** does it correspond to a typedef struct field
1507 if (ctype_isPointer (ct
))
1509 ctype ctb
= ctype_realType (ctype_baseArrayPtr (ct
));
1511 if (ctype_isStructorUnion (ctb
) &&
1512 uentry_isValid (uentryList_lookupField
1513 (ctype_getFields (ctb
), fieldname
)))
1515 cstring fname
= cstring_copy (fieldname
);
1517 ret
= sRef_buildArrow (rec
, fname
);
1518 cstring_markOwned (fname
);
1527 return sRef_undefined
;
1533 ** o replace anything in modifies that is bound with let with value
1534 ** o replace spec variables with internal state
1535 ** o replace paramaters with paramno identifiers
1536 ** o replace globals with their usymid's
1537 ** o make everything sRefs
1540 static /*@exposed@*/ sRef
fixTermNode (termNode n
, fcnNode f
, uentryList cl
)
1542 if (n
!= (termNode
) 0)
1552 cstring s
= ltoken_getRawString (n
->literal
);
1553 termNode tl
= getLetDecl (s
, f
);
1555 if (tl
!= (termNode
) 0)
1557 return (fixTermNode (tl
, f
, cl
));
1561 int i
= getParamNo (s
, f
);
1565 usymId usym
= usymtab_getId (s
);
1567 if (usymId_isInvalid (usym
))
1569 if (usymtab_existsEither (s
))
1571 return sRef_makeSpecState ();
1575 llcontbuglit ("Invalid symbol in modifies list");
1576 return sRef_undefined
;
1580 return (sRef_makeGlobal (usym
, ctype_unknown
, stateInfo_currentLoc ()));
1585 sRef p
= sRef_makeParam (i
, ctype_unknown
, stateInfo_currentLoc ());
1590 case TRM_APPLICATION
:
1592 nameNode nn
= n
->name
;
1594 if (nn
!= (nameNode
) 0)
1598 /* must we handle n->given ? skip for now */
1601 (message ("fixTermNode: expect non-empty nameNode: "
1602 "TRM_APPLICATION: %q",
1603 nameNode_unparse (nn
)));
1609 sr
= processTermNode (nn
->content
.opform
, n
->args
, f
, cl
);
1614 return sRef_undefined
;
1616 case TRM_UNCHANGEDALL
:
1617 case TRM_UNCHANGEDOTHERS
:
1619 case TRM_QUANTIFIER
:
1620 return sRef_undefined
;
1624 return sRef_undefined
;
1628 /*@only@*/ sRefSet
fixModifies (fcnNode f
, uentryList cl
)
1630 static bool shownWarning
= FALSE
;
1631 modifyNode m
= f
->modify
;
1632 sRefSet sl
= sRefSet_new ();
1634 if (m
!= (modifyNode
) 0)
1636 if (m
->hasStoreRefList
)
1638 storeRefNodeList srefs
= m
->list
;
1640 storeRefNodeList_elements (srefs
, i
)
1642 if (storeRefNode_isObj (i
) || storeRefNode_isType (i
))
1646 fileloc loc
= fileloc_fromTok (f
->name
);
1649 ("%q: Warning: object and type modifications "
1650 "not understood by Splint",
1651 fileloc_unparse (loc
)));
1653 shownWarning
= TRUE
;
1656 else if (storeRefNode_isSpecial (i
))
1658 sl
= sRefSet_insert (sl
, i
->content
.ref
);
1660 else if (storeRefNode_isTerm (i
))
1662 sRef s
= fixTermNode (i
->content
.term
, f
, cl
);
1664 if (sRef_isKnown (s
))
1666 sl
= sRefSet_insert (sl
, s
);
1673 } end_storeRefNodeList_elements
;
1681 static /*@only@*/ cstring
1682 paramNode_name (paramNode x
)
1684 return (typeExpr_name (x
->paramdecl
));
1687 static /*@only@*/ uentry
1688 paramNode_toUentry (paramNode p
)
1690 if (p
!= (paramNode
) 0)
1692 if (p
->kind
== PELIPSIS
)
1694 return uentry_makeElipsisMarker ();
1698 qtype ct
= convertLclTypeSpecNode (p
->type
);
1699 ctype cr
= convertTypeExpr (qtype_getType (ct
), p
->paramdecl
);
1700 cstring pname
= (p
->paramdecl
== (typeExpr
)0) ? cstring_undefined
1701 : paramNode_name (p
);
1702 uentry ue
= uentry_makeVariableParam (pname
, cr
, g_currentloc
);
1704 uentry_reflectQualifiers (ue
, qtype_getQuals (ct
));
1711 llcontbuglit ("paramNode_toUentry: NULL");
1712 return uentry_undefined
;
1718 paramNodeList_toUentryList (paramNodeList p
)
1720 uentryList cl
= uentryList_new ();
1722 if (paramNodeList_isNull (p
)) return (cl
);
1724 paramNodeList_elements (p
, current
)
1726 cl
= uentryList_add (cl
, paramNode_toUentry (current
));
1727 } end_paramNodeList_elements
;