/* ** Splint - annotation-assisted static program checker ** Copyright (C) 1994-2003 University of Virginia, ** Massachusetts Institute of Technology ** ** This program is free software; you can redistribute it and/or modify it ** under the terms of the GNU General Public License as published by the ** Free Software Foundation; either version 2 of the License, or (at your ** option) any later version. ** ** This program is distributed in the hope that it will be useful, but ** WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** ** The GNU General Public License is available from http://www.gnu.org/ or ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ** MA 02111-1307, USA. ** ** For information on splint: info@splint.org ** To report a bug: splint-bug@splint.org ** For more information: http://www.splint.org */ /* ** nameChecks.c */ # include "splintMacros.nf" # include "basic.h" # include "nameChecks.h" static bool checkCzechName (uentry p_ue, flagcode p_czechflag, bool p_report) /*@modifies p_ue, g_warningstream@*/ ; static bool checkSlovakName (uentry p_ue, flagcode p_slovakflag, bool p_report) /*@modifies p_ue, g_warningstream@*/ ; static cstring czechPrefix (cstring name) { return (cstring_beforeChar (name, '_')); } static cstring slovakPrefix (cstring name) { size_t i = 0; cstring_chars (name, c) { if (isupper ((unsigned char) c)) { return (cstring_prefix (name, i)); } i++; } end_cstring_chars; return cstring_undefined; } static flagcode excludeCodes [] = { FLG_MACROVARPREFIXEXCLUDE, FLG_TAGPREFIXEXCLUDE, FLG_ENUMPREFIXEXCLUDE, FLG_FILESTATICPREFIXEXCLUDE, FLG_GLOBPREFIXEXCLUDE, FLG_TYPEPREFIXEXCLUDE, FLG_EXTERNALPREFIXEXCLUDE, FLG_UNCHECKEDMACROPREFIXEXCLUDE, FLG_LOCALPREFIXEXCLUDE, INVALID_FLAG } ; /*@iter excludeFlagCodes (yield flagcode code);@*/ # define excludeFlagCodes(m_c) \ { int m_i = 0; while (flagcode_isValid (excludeCodes[m_i])) \ { flagcode m_c = excludeCodes[m_i]; m_i++; # define end_excludeFlagCodes }} static bool matchPrefixChar (int nc, int pc) { if (nc == pc) { return TRUE; } else { switch (pc) { case PFX_UPPERCASE: return isupper (nc); case PFX_LOWERCASE: return islower (nc); case PFX_ANY: return TRUE; case PFX_DIGIT: return isdigit (nc); case PFX_NOTUPPER: return !isupper (nc); case PFX_NOTLOWER: return !islower (nc); case PFX_ANYLETTER: return isalpha (nc); case PFX_ANYLETTERDIGIT: return (isdigit (nc) || isalpha (nc)); default: return FALSE; } } BADEXIT; } static bool matchPrefix (cstring name, cstring prefix) { if (cstring_isUndefined (name) || cstring_isUndefined (prefix)) { return TRUE; } else { size_t namelen = cstring_length (name); int last = (int) '\0'; size_t n = 1; cstring_chars (prefix, pc) { int nc; if (pc == '*') { n++; while (n <= namelen) { nc = (int) cstring_getChar (name, n); if (!matchPrefixChar (nc, last)) { return FALSE; } n++; } return TRUE; } else { if (n > namelen) { if (namelen > 1 && (cstring_length (prefix) >= n + 1) && cstring_getChar (prefix, n + 1) == '*') { return TRUE; } else { return FALSE; } } nc = (int) cstring_getChar (name, n); if (!matchPrefixChar (nc, (int) pc)) { return FALSE; } } last = (int) pc; n++; } end_cstring_chars; return TRUE; } } static flagcode namespaceExcluded (flagcode code) /*@*/ { switch (code) { case FLG_MACROVARPREFIXEXCLUDE: return (FLG_MACROVARPREFIX); case FLG_TAGPREFIXEXCLUDE: return (FLG_TAGPREFIX); case FLG_ENUMPREFIXEXCLUDE: return (FLG_ENUMPREFIX); case FLG_FILESTATICPREFIXEXCLUDE: return (FLG_FILESTATICPREFIX); case FLG_GLOBPREFIXEXCLUDE: return (FLG_GLOBPREFIX); case FLG_TYPEPREFIXEXCLUDE: return (FLG_TYPEPREFIX); case FLG_EXTERNALPREFIXEXCLUDE: return (FLG_EXTERNALPREFIX); case FLG_UNCHECKEDMACROPREFIXEXCLUDE: return (FLG_UNCHECKEDMACROPREFIX); case FLG_LOCALPREFIXEXCLUDE: return (FLG_LOCALPREFIX); case FLG_ITERPREFIXEXCLUDE: return (FLG_ITERPREFIX); case FLG_CONSTPREFIXEXCLUDE: return (FLG_CONSTPREFIX); BADDEFAULT; } } static /*@observer@*/ cstring namespaceName (flagcode flag) /*@*/ { switch (flag) { case FLG_MACROVARPREFIX: return cstring_makeLiteralTemp ("macro variable"); case FLG_TAGPREFIX: return cstring_makeLiteralTemp ("tag"); case FLG_ENUMPREFIX: return cstring_makeLiteralTemp ("enum member"); case FLG_TYPEPREFIX: return cstring_makeLiteralTemp ("user-defined type"); case FLG_FILESTATICPREFIX: return cstring_makeLiteralTemp ("file static"); case FLG_GLOBPREFIX: return cstring_makeLiteralTemp ("global variable"); case FLG_EXTERNALPREFIX: return cstring_makeLiteralTemp ("external"); case FLG_LOCALPREFIX: return cstring_makeLiteralTemp ("local variable"); case FLG_CONSTPREFIX: return cstring_makeLiteralTemp ("constant"); case FLG_ITERPREFIX: return cstring_makeLiteralTemp ("iter"); case FLG_UNCHECKEDMACROPREFIX: return cstring_makeLiteralTemp ("unchecked macro"); BADDEFAULT; } } void checkPrefix (uentry ue) { cstring name = cstring_undefined; flagcode flag; if (uentry_isExpandedMacro (ue)) { flag = FLG_UNCHECKEDMACROPREFIX; } else if (uentry_isAnyTag (ue)) { flag = FLG_TAGPREFIX; } else if (uentry_isEnumConstant (ue)) { flag = FLG_ENUMPREFIX; } else if (uentry_isDatatype (ue)) { flag = FLG_TYPEPREFIX; } else if (uentry_isFileStatic (ue)) { flag = FLG_FILESTATICPREFIX; } else if (uentry_isGlobalVariable (ue)) { flag = FLG_GLOBPREFIX; } else if (uentry_isVariable (ue)) { if (uentry_isRefParam (ue)) { return; /* already checked param */ } if (context_inMacro ()) { if (uentry_isAnyParam (ue)) { if (uentry_isYield (ue)) { flag = FLG_MACROVARPREFIX; } else { flag = FLG_LOCALPREFIX; } } else { flag = FLG_MACROVARPREFIX; } } else { flag = FLG_LOCALPREFIX; } } else if (uentry_isConstant (ue)) { flag = FLG_CONSTPREFIX; } else if (uentry_isIter (ue)) { flag = FLG_ITERPREFIX; } else if (uentry_isExported (ue)) { flag = FLG_EXTERNALPREFIX; } else { llcontbug (message ("What is it: %q", uentry_unparseFull (ue))); return; } if (flag == FLG_TYPEPREFIX || flag == FLG_GLOBPREFIX || flag == FLG_ENUMPREFIX || flag == FLG_CONSTPREFIX) { if (flag == FLG_ENUMPREFIX) { if (!context_getFlag (flag)) { flag = FLG_CONSTPREFIX; } } if (!context_getFlag (flag)) { flag = FLG_EXTERNALPREFIX; } } if (context_getFlag (flag)) { name = uentry_observeRealName (ue); if (!matchPrefix (name, context_getString (flag))) { llassert (flag != FLG_NAMECHECKS); if (optgenerror2 (flag, FLG_NAMECHECKS, message ("%s %s name is not consistent with %s " "namespace prefix \"%s\"", uentry_ekindName (ue), name, namespaceName (flag), context_getString (flag)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } } excludeFlagCodes (code) { bool check = FALSE; if (context_getFlag (code)) { /*@-loopswitchbreak@*/ switch (code) { case FLG_MACROVARPREFIXEXCLUDE: check = (flag != FLG_MACROVARPREFIX); break; case FLG_TAGPREFIXEXCLUDE: check = (flag != FLG_TAGPREFIX); break; case FLG_ENUMPREFIXEXCLUDE: check = (flag != FLG_ENUMPREFIX); break; case FLG_FILESTATICPREFIXEXCLUDE: check = (flag != FLG_FILESTATICPREFIX); break; case FLG_GLOBPREFIXEXCLUDE: check = (flag != FLG_GLOBPREFIX); break; case FLG_TYPEPREFIXEXCLUDE: check = (flag != FLG_TYPEPREFIX); break; case FLG_EXTERNALPREFIXEXCLUDE: check = (flag != FLG_EXTERNALPREFIX && flag != FLG_GLOBPREFIX && flag != FLG_TYPEPREFIX && flag != FLG_UNCHECKEDMACROPREFIX); break; case FLG_UNCHECKEDMACROPREFIXEXCLUDE: check = (flag != FLG_UNCHECKEDMACROPREFIX); break; case FLG_LOCALPREFIXEXCLUDE: check = (flag != FLG_LOCALPREFIX); break; case FLG_CONSTPREFIXEXCLUDE: check = (flag != FLG_CONSTPREFIX); break; case FLG_ITERPREFIXEXCLUDE: check = (flag != FLG_ITERPREFIX); break; BADDEFAULT; } /*@=loopswitchbreak@*/ if (check) { flagcode rcode = namespaceExcluded (code); cstring pstring = context_getString (rcode); if (cstring_isDefined (pstring)) { if (cstring_isUndefined (name)) { name = uentry_observeRealName (ue); } if (matchPrefix (name, context_getString (rcode))) { if (optgenerror2 (code, FLG_NAMECHECKS, message ("%s %s name is not a %s (it is a %s), " "but matches the %s " "namespace prefix \"%s\"", uentry_ekindName (ue), name, namespaceName (rcode), namespaceName (flag), namespaceName (rcode), context_getString (rcode)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } } } } } end_excludeFlagCodes ; } static void checkNationalName (uentry ue) { flagcode czechflag; flagcode slovakflag; flagcode czechoslovakflag; bool gcf, gsf, gcsf; if (uentry_isFunction (ue) || uentry_isIter (ue) || uentry_isEndIter (ue)) { czechflag = FLG_CZECHFUNCTIONS; slovakflag = FLG_SLOVAKFUNCTIONS; czechoslovakflag = FLG_CZECHOSLOVAKFUNCTIONS; } else if (uentry_isExpandedMacro (ue)) { czechflag = FLG_CZECHMACROS; slovakflag = FLG_SLOVAKMACROS; czechoslovakflag = FLG_CZECHOSLOVAKMACROS; } else if (uentry_isVariable (ue)) { if (uentry_isGlobalVariable (ue) && context_getFlag (FLG_GLOBPREFIX)) { /* prefix checks supercede national naming checks */ return; } czechflag = FLG_CZECHVARS; slovakflag = FLG_SLOVAKVARS; czechoslovakflag = FLG_CZECHOSLOVAKVARS; } else if (uentry_isConstant (ue)) { if (uentry_isGlobalVariable (ue) && context_getFlag (FLG_CONSTPREFIX)) { /* prefix checks supercede national naming checks */ return; } czechflag = FLG_CZECHCONSTANTS; slovakflag = FLG_SLOVAKCONSTANTS; czechoslovakflag = FLG_CZECHOSLOVAKCONSTANTS; } else { if (uentry_isAnyTag (ue) || uentry_isEnumConstant (ue)) { return; /* no errors for tags */ } llassert (uentry_isDatatype (ue)); czechflag = FLG_CZECHTYPES; slovakflag = FLG_SLOVAKTYPES; czechoslovakflag = FLG_CZECHOSLOVAKTYPES; } gcf = context_getFlag (czechflag); gsf = context_getFlag (slovakflag); gcsf = context_getFlag (czechoslovakflag); if (gcf || (uentry_isFunction (ue) && context_getFlag (FLG_ACCESSCZECH))) { (void) checkCzechName (ue, czechflag, gcf); } if (gsf || (uentry_isFunction (ue) && context_getFlag (FLG_ACCESSSLOVAK))) { (void) checkSlovakName (ue, slovakflag, gsf); } if (gcsf) { if (uentry_isDatatype (ue)) { /* May not have either _'s or uppercase letter */ cstring name = uentry_rawName (ue); int charno = 1; cstring_chars (name, c) { if (isupper ((unsigned char) c)) { if (optgenerror2 (FLG_CZECHOSLOVAKTYPES, FLG_NAMECHECKS, message ("%s %q name violates Czechoslovak naming convention. " "Czechoslovak datatype names should not use uppercase " "letters.", uentry_ekindName (ue), uentry_getName (ue)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } break; } if (c == '_' && charno != 2 && charno != 3) { if (optgenerror2 (FLG_CZECHOSLOVAKTYPES, FLG_NAMECHECKS, message ("%s %q name violates Czechoslovak naming " "convention. Czechoslovak datatype names " "should not use the _ charater.", uentry_ekindName (ue), uentry_getName (ue)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } break; } charno++; } end_cstring_chars; } else { bool okay = checkCzechName (ue, czechflag, FALSE); /* still need to call, to set access */ okay |= checkSlovakName (ue, slovakflag, FALSE); if (!okay) { if (optgenerror2 (czechoslovakflag, FLG_NAMECHECKS, message ("%s %q name is not consistent with Czechoslovak " "naming convention.", uentry_ekindName (ue), uentry_getName (ue)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } } } } static bool checkCzechName (uentry ue, flagcode czechflag, bool report) { if (uentry_isDatatype (ue)) { /* ** Czech datatypes may not have _'s, except if there are 1 or 2 characters ** before the only _. */ cstring name = uentry_rawName (ue); int charno = 1; cstring_chars (name, c) { if (c == '_' && charno != 2 && charno != 3) { if (report) { if (optgenerror2 (FLG_CZECHTYPES, FLG_NAMECHECKS, message ("%s %q name violates Czech naming convention. " "Czech datatype names should not use the _ charater.", uentry_ekindName (ue), uentry_getName (ue)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } return FALSE; } charno++; } end_cstring_chars; } else { typeIdSet acc = context_fileAccessTypes (); cstring pfx = czechPrefix (uentry_rawName (ue)); if (cstring_isEmpty (pfx)) { if (uentry_isVariable (ue) || uentry_isConstant (ue)) { ctype ct = uentry_getType (ue); if (ctype_isAbstract (ct) && context_hasAccess (ctype_typeId (ct))) { if (report) { if (optgenerror2 (czechflag, FLG_NAMECHECKS, message ("%s %q name is not consistent with Czech " "naming convention. The name should " "begin with %s_", uentry_ekindName (ue), uentry_getName (ue), ctype_unparse (ct)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } else if (uentry_isFunction (ue) || uentry_isIter (ue)) { if (typeIdSet_isEmpty (acc)) { ; /* okay - should not be czech name */ } else { if (report) { if (optgenerror2 (czechflag, FLG_NAMECHECKS, message ("%s %q name is not consistent with Czech " "naming convention. Accessible types: %q", uentry_ekindName (ue), uentry_getName (ue), typeIdSet_unparse (acc)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } else { ; } } else { if (usymtab_existsTypeEither (pfx)) { ctype ct = usymtab_lookupAbstractType (pfx); typeId tid; if (ctype_isUA (ct)) { tid = ctype_typeId (ct); if (ctype_isUser (ct) || context_hasAccess (tid)) { ; } else { if (context_getFlag (FLG_ACCESSCZECH) || context_getFlag (FLG_ACCESSCZECHOSLOVAK)) { if (!uentry_isVar (ue)) { uentry_addAccessType (ue, tid); } } else { if (report) { if (llgenhinterror (czechflag, message ("%s %q name violates Czech naming " "convention. Czech prefix %s names " "an abstract type that is " "not accessible.", uentry_ekindName (ue), uentry_getName (ue), pfx), cstring_makeLiteral ("Use +accessczech to allow access to " "type in functions " "named _."), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } } else if (ctype_isManifestBool (ct)) { if (context_canAccessBool ()) { ; } else { if (context_getFlag (FLG_ACCESSCZECH) || context_getFlag (FLG_ACCESSCZECHOSLOVAK)) { if (!uentry_isVar (ue)) { tid = usymtab_getTypeId (context_getBoolName ()); uentry_addAccessType (ue, tid); } } else { if (report) { if (llgenhinterror (czechflag, message ("%s %q name violates Czech naming " "convention. Type bool is not accessible.", uentry_ekindName (ue), uentry_getName (ue)), cstring_makeLiteral ("Use +accessczech to allow access to " "type in functions named _."), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } } else { ; } } else { if (cstring_equalLit (pfx, "int") || cstring_equalLit (pfx, "char") || cstring_equalLit (pfx, "short") || cstring_equalLit (pfx, "long") || cstring_equalLit (pfx, "unsigned") || cstring_equalLit (pfx, "signed") || cstring_equalLit (pfx, "float") || cstring_equalLit (pfx, "double")) { ; /* built-in types */ } else { /* no accessible types, could match module name */ if (cstring_equal (pfx, context_moduleName ())) { ; } else { if (report) { if (optgenerror2 (czechflag, FLG_NAMECHECKS, message ("%s %q name violates Czech naming convention. " "Czech prefix %s is not the name of a type.", uentry_ekindName (ue), uentry_getName (ue), pfx), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } } } cstring_free (pfx); } return TRUE; } static bool checkSlovakName (uentry ue, flagcode slovakflag, bool report) { if (uentry_isDatatype (ue)) { /* ** Slovak datatypes may not have uppercase letters. */ if (context_getFlag (FLG_SLOVAK)) { cstring name = uentry_rawName (ue); cstring_chars (name, c) { if (isupper ((unsigned char) c)) { if (report) { if (optgenerror2 (FLG_SLOVAKTYPES, FLG_NAMECHECKS, message ("%s %q name violates Slovak naming convention. " "Slovak datatype names should not use uppercase " "letters.", uentry_ekindName (ue), uentry_getName (ue)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } return FALSE; } } end_cstring_chars; } } else { typeIdSet acc = context_fileAccessTypes (); cstring pfx = slovakPrefix (uentry_rawName (ue)); if (cstring_isEmpty (pfx)) { if (typeIdSet_isEmpty (acc)) { ; /* okay - should not be slovak name */ } else { if (uentry_isFunction (ue)) { if (report) { if (optgenerror2 (slovakflag, FLG_NAMECHECKS, message ("%s %q name is not consistent with Slovak " "naming convention. Accessible types: %q", uentry_ekindName (ue), uentry_getName (ue), typeIdSet_unparse (acc)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } else { ctype ct = uentry_getType (ue); if (ctype_isUA (ct)) { if (report) { if (optgenerror2 (slovakflag, FLG_NAMECHECKS, message ("%s %q name is not consistent with " "Slovak naming convention. The " "name should begin with %s followed " "by an uppercase letter.", uentry_ekindName (ue), uentry_getName (ue), ctype_unparse (ct)), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } } } else { if (usymtab_existsTypeEither (pfx)) { ctype ct = usymtab_lookupAbstractType (pfx); typeId tid; if (ctype_isUA (ct)) { tid = ctype_typeId (ct); if (ctype_isUser (ct) || context_hasAccess (tid)) { ; } else { if (context_getFlag (FLG_ACCESSSLOVAK) || context_getFlag (FLG_ACCESSCZECHOSLOVAK)) { if (!uentry_isVar (ue)) { uentry_addAccessType (ue, tid); } } else { if (report) { if (llgenhinterror (slovakflag, message ("%s %q name violates Slovak naming " "convention. Slovak prefix %s names " "an abstract type that is not accessible.", uentry_ekindName (ue), uentry_getName (ue), pfx), cstring_makeLiteral ("Use +accessslovak to allow access to " "type in functions named _."), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } } else if (ctype_isManifestBool (ct)) { if (context_canAccessBool ()) { ; } else { if (context_getFlag (FLG_ACCESSSLOVAK) || context_getFlag (FLG_ACCESSCZECHOSLOVAK)) { if (!uentry_isVar (ue)) { tid = usymtab_getTypeId (context_getBoolName ()); uentry_addAccessType (ue, tid); } } else { if (report) { if (llgenhinterror (slovakflag, message ("%s %q name violates Slovak naming convention. " "Type bool is not accessible.", uentry_ekindName (ue), uentry_getName (ue)), cstring_makeLiteral ("Use +accessslovak to allow access to " "type in functions named _."), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } } else { ; } } else { if (cstring_equalLit (pfx, "int") || cstring_equalLit (pfx, "char") || cstring_equalLit (pfx, "short") || cstring_equalLit (pfx, "long") || cstring_equalLit (pfx, "unsigned") || cstring_equalLit (pfx, "signed") || cstring_equalLit (pfx, "float") || cstring_equalLit (pfx, "double")) { ; /* built-in types */ } else { /* no accessible types, could match module name */ if (cstring_equal (pfx, context_moduleName ())) { ; } else { if (report) { if (optgenerror2 (slovakflag, FLG_NAMECHECKS, message ("%s %q name violates Slovak naming convention. " "Slovak prefix %s is not the name of a type.", uentry_ekindName (ue), uentry_getName (ue), pfx), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } cstring_free (pfx); return FALSE; } } } } cstring_free (pfx); } return TRUE; } void checkExternalName (uentry ue) { if (!uentry_isStatic (ue) && uentry_hasName (ue)) { checkNationalName (ue); } else { ; } } void checkLocalName (/*@unused@*/ uentry ue) { /* ** No local checks (yet) */ return; } void checkFileScopeName (/*@unused@*/ uentry ue) { /* ** No file scope checks (yet) */ /* add a file scope naming convention policy? */ return; } /* ** Checks a name used by user source is not reserved by ANSI ** (or for future library functions). ** ** The restrictions are described in X3.159-1989: 4.13 */ /*@constant int NRESERVEDNAMES; @*/ # define NRESERVEDNAMES 201 /*@constant int NCPPNAMES@*/ # define NCPPNAMES 39 void checkCppName (uentry ue) { cstring name = uentry_observeRealName (ue); static ob_mstring cppNames[NCPPNAMES] = { "and", "and_eq", "asm", "bitand", "bitor", "bool", /* gasp: "bool", is special for splint */ "catch", "class", "compl", "const_class", "delete", "dynamic_cast", "false", "friend", "inline", "mutable", "namespace", "new", "not", "not_eq", "operator", "or", "or_eq", "overload", "private", "protected", "public", "reinterpret_cast", "static_cast", "template", "this", "throw", "true", "try", "typeid", "using", "virtual", "xor", "xor_eq" } ; if (cstring_isDefined (cstring_bsearch (name, &cppNames[0], NCPPNAMES))) { if (optgenerror2 (FLG_CPPNAMES, FLG_NAMECHECKS, message ("Name %s is a keyword or reserved word in C++", name), uentry_whereLast (ue))) { uentry_setHasNameError (ue); } } } void checkAnsiName (uentry ue) { bool hasError = FALSE; cstring name = uentry_observeRealName (ue); size_t length = cstring_length (name); char fchar = (length >= 1) ? cstring_firstChar (name) : '\0'; char schar = (length >= 2) ? cstring_secondChar (name) : '\0'; char tchar = (length >= 3) ? cstring_getChar (name, 3) : '\0'; char rchar = (length >= 4) ? cstring_getChar (name, 4) : '\0'; /* ** reservedNames ** taken from Linden, "Expert C Programming", p. 126-8. ** invariant: must be sorted (case-insensitive, lexicographically) ** must end with NULL */ static ob_mstring reservedNames[NRESERVEDNAMES] = { # include "reservedNames.nf" } ; # if 0 /* ** This code is for checking reservedNames.nf */ { int i = 0; char *lastname = NULL; char *name; while ((name = reservedNames[i]) != NULL) { llassertprint (lastname == NULL || strcmp (name, lastname) > 0, ("%s / %s", lastname, name)); lastname = name; i++; } nreservedNames = i - 1; } # endif if (fileloc_isSystemFile (uentry_whereLast (ue)) || fileloc_isBuiltin (uentry_whereLast (ue))) { return; /* no errors for system files */ } if (cstring_isDefined (cstring_bsearch (name, &reservedNames[0], NRESERVEDNAMES))) { hasError |= optgenerror2 (FLG_ISORESERVED, FLG_NAMECHECKS, message ("Name %s is reserved for the standard library", name), uentry_whereLast (ue)); } if (uentry_isFileStatic (ue) || uentry_isVisibleExternally (ue) || uentry_isAnyTag (ue) || context_getFlag (FLG_ISORESERVEDLOCAL)) { if (fchar == '_') { hasError |= optgenerror2 (FLG_ISORESERVED, FLG_NAMECHECKS, message ("Name %s is in the implementation name space (any identifier " "beginning with underscore)", name), uentry_whereLast (ue)); } } else { /* ** ISO 7.1.3: ** - All identifiers that begin with an underscore and either an uppercase ** letter or another underscore are always reserved for any use. */ if (fchar == '_' && (schar == '_' || isupper ((int) schar))) { hasError |= optgenerror2 (FLG_ISORESERVED, FLG_NAMECHECKS, message ("Name %s is in the implementation name space (any identifier " "beginning with underscore and either an uppercase letter or " "another underscore is always reserved for any use)", name), uentry_whereLast (ue)); } } /* ** 4.13.1 Errors ** ** Macros that begin with E and a digit or E and an uppercase letter ... */ if (fchar == 'E' && (isdigit ((int) schar) || isupper ((int) schar))) { hasError |= optgenerror2 (FLG_ISORESERVED, FLG_NAMECHECKS, message ("Name %s is reserved for future library extensions. " "Macros beginning with E and a digit or uppercase letter " "may be added to . (ISO99:7.26.3)", name), uentry_whereLast (ue)); } /* ** 4.13.3 Localization ** ** Macros that begin with LC_ and an uppercase letter ... */ if (length >= 4 && ((fchar == 'L') && (schar == 'C') && (tchar == '_')) && (isupper ((int) rchar))) { hasError |= optgenerror2 (FLG_ISORESERVED, FLG_NAMECHECKS, message ("Name %s is reserved for future library extensions. " "Macros beginning with \"LC_\" and an uppercase letter may " "be added to . (ISO99:7.26.5)", name), uentry_whereLast (ue)); } /* ** 4.13.5 Signal Handling ** ** Macros that begin with either SIG or SIG_ and an uppercase letter or... */ if (fchar == 'S' && schar == 'I' && tchar == 'G' && ((rchar == '_' && ((length >= 5 && isupper ((int) cstring_getChar (name, 5))))) || (isupper ((int) rchar)))) { hasError |= optgenerror2 (FLG_ISORESERVED, FLG_NAMECHECKS, message ("Name %s is reserved for future library extensions. " "Macros that begin with SIG and an uppercase letter or SIG_ " "and an uppercase letter may be added to " ". (ISO99:7.14)", name), uentry_whereLast (ue)); } /* ** evans - 2002-12-16: added this check (even though it is not required by ISO) */ if (fchar == 'S' && schar == 'A' && tchar == '_') { hasError |= optgenerror2 (FLG_ISORESERVED, FLG_NAMECHECKS, message ("Name %s may be defined as a macro by Linux library. " "It is not research by the ISO specification, but may produce conflicts on some systems.", name), uentry_whereLast (ue)); } if ((uentry_isVisibleExternally (ue) && !uentry_isAnyTag (ue)) || context_getFlag (FLG_ISORESERVEDLOCAL)) { flagcode flg; DPRINTF (("Okay...: %s", uentry_unparse (ue))); if (uentry_isVisibleExternally (ue) && !uentry_isAnyTag (ue)) { flg = FLG_ISORESERVED; } else { flg = FLG_ISORESERVEDLOCAL; } DPRINTF (("ue: %s", uentry_unparseFull (ue))); /* ** These restrictions only apply to identifiers with global linkage. */ /* ** 4.13.2 Character Handling ** ** Function names that begin with either "is" or "to" and a lowercase letter ... */ if (((fchar == 'i' && schar == 's') || (fchar == 't' && schar == 'o')) && (islower ((int) tchar))) { hasError |= optgenerror2 (flg, FLG_NAMECHECKS, message ("Name %s is reserved for future library extensions. " "Functions beginning with \"is\" or \"to\" and a lowercase " "letter may be added to . (ISO99:7.26.2)", name), uentry_whereLast (ue)); DPRINTF (("Externally visible: %s / %s", uentry_unparseFull (ue), bool_unparse (uentry_isVisibleExternally (ue)))); } /* ** 4.13.4 Mathematics ** ** The names of all existing functions declared in the header, ** suffixed with f or l... */ DPRINTF (("Check name: %s", name)); if ((cstring_lastChar (name) == 'f' || cstring_lastChar (name) == 'l') && (((length == 4) && ((cstring_equalPrefixLit (name, "cos") || cstring_equalPrefixLit (name, "sin") || cstring_equalPrefixLit (name, "tan") || cstring_equalPrefixLit (name, "exp") || cstring_equalPrefixLit (name, "log") || cstring_equalPrefixLit (name, "pow")))) || ((length == 5) && ((cstring_equalPrefixLit (name, "acos") || cstring_equalPrefixLit (name, "asin") || cstring_equalPrefixLit (name, "atan") || cstring_equalPrefixLit (name, "cosh") || cstring_equalPrefixLit (name, "sinh") || cstring_equalPrefixLit (name, "sqrt") || cstring_equalPrefixLit (name, "ceil") || cstring_equalPrefixLit (name, "fabs") || cstring_equalPrefixLit (name, "fmod") || cstring_equalPrefixLit (name, "tanh") || cstring_equalPrefixLit (name, "modf")))) || ((length == 6) && ((cstring_equalPrefixLit (name, "atan2") || cstring_equalPrefixLit (name, "floor") || cstring_equalPrefixLit (name, "frexp") || cstring_equalPrefixLit (name, "ldexp") || cstring_equalPrefixLit (name, "log10")))))) { hasError |= optgenerror2 (flg, FLG_NAMECHECKS, message ("Name %s is reserved for future library extensions. " "The names of all existing functions in suffixed " "with 'f' or 'l' may be added to . (ISO:7.26.1)", name), uentry_whereLast (ue)); } /* ** 4.13.6 Input/Output ** ** (nothing to check) */ /* ** 4.13.7 General Utilities ** ** Functions names that begin with str and a lowercase letter may be added to . */ if (fchar == 's' && schar == 't' && tchar == 'r' && (islower ((int) rchar))) { hasError |= optgenerror2 (flg, FLG_NAMECHECKS, message ("Name %s is reserved for future library extensions. " "Functions that begin with \"str\" and a lowercase letter " "may be added to or . (ISO99:7.26.9)", name), uentry_whereLast (ue)); } /* ** 4.13.8 String Handling ** ** Function names that begin with str, mem, or wcs and a lowercase letter ... ** ** (Note: already checked "str" above.) */ if (((fchar == 'm' && schar == 'e' && tchar == 'm') || (fchar == 'w' && schar == 'c' && tchar == 's')) && (islower ((int) rchar))) { hasError |= optgenerror2 (flg, FLG_NAMECHECKS, message ("Name %s is reserved for future library extensions. " "Functions that begin with \"mem\" or \"wcs\" and a " "lowercase letter may be added to . (ISO:7.26.11)", name), uentry_whereLast (ue)); } } else { DPRINTF (("Not checked: [%s] %s", bool_unparse (uentry_isVisibleExternally (ue)), uentry_unparseFull (ue))); } if (hasError) { uentry_setHasNameError (ue); } } void checkParamNames (uentry ue) { cstring fpfx = context_getString (FLG_DECLPARAMPREFIX); bool noformal = context_getFlag (FLG_DECLPARAMNAME); llassert (uentry_isFunction (ue)); if (cstring_isDefined (fpfx) || noformal) { uentryList params = uentry_getParams (ue); uentryList_elements (params, p) { if (uentry_hasName (p)) { if (noformal && !cstring_isDefined (fpfx)) { if (optgenerror2 (FLG_DECLPARAMNAME, FLG_NAMECHECKS, message ("Declaration parameter has name: %q", uentry_getName (p)), uentry_whereLast (p))) { uentry_setHasNameError (p); } } else { cstring pname = uentry_observeRealName (p); if (!cstring_equalPrefix (pname, fpfx)) { if (context_getFlag (FLG_NAMECHECKS)) { if (optgenerror2 (FLG_DECLPARAMPREFIX, FLG_NAMECHECKS, message ("Declaration parameter name %s does not begin " "with protoparamprefix (%s)", pname, fpfx), uentry_whereLast (p))) { uentry_setHasNameError (p); } } } } } } end_uentryList_elements ; } } /* not yet checked: POSIX p. 527 - applications should not declare any symbols that end _MAX */