]> andersk Git - splint.git/blob - src/nameChecks.c
20e8fa5245eb9c978dce80829dbcf04ca5472f3f
[splint.git] / src / nameChecks.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
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 **
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
23 */
24 /*
25 ** nameChecks.c
26 */
27
28 # include "splintMacros.nf"
29 # include "basic.h"
30 # include "nameChecks.h"
31
32 static bool checkCzechName (uentry p_ue, flagcode p_czechflag, bool p_report)
33   /*@modifies p_ue, g_warningstream@*/ ;
34
35 static bool checkSlovakName (uentry p_ue, flagcode p_slovakflag, bool p_report)
36   /*@modifies p_ue, g_warningstream@*/ ;
37
38 static cstring czechPrefix (cstring name)
39 {
40   return (cstring_beforeChar (name, '_'));
41 }
42
43 static cstring slovakPrefix (cstring name)
44 {
45   size_t i = 0;
46
47   cstring_chars (name, c)
48     {
49       if (isupper ((unsigned char) c))
50         {
51           return (cstring_prefix (name, i));
52         }
53       i++;
54     } end_cstring_chars;
55
56   return cstring_undefined;
57 }
58
59 static flagcode excludeCodes [] = 
60  {
61    FLG_MACROVARPREFIXEXCLUDE,
62    FLG_TAGPREFIXEXCLUDE,
63    FLG_ENUMPREFIXEXCLUDE,
64    FLG_FILESTATICPREFIXEXCLUDE,
65    FLG_GLOBPREFIXEXCLUDE,
66    FLG_TYPEPREFIXEXCLUDE,
67    FLG_EXTERNALPREFIXEXCLUDE,
68    FLG_UNCHECKEDMACROPREFIXEXCLUDE,
69    FLG_LOCALPREFIXEXCLUDE,
70    INVALID_FLAG
71    } ;
72
73 /*@iter excludeFlagCodes (yield flagcode code);@*/
74 # define excludeFlagCodes(m_c) \
75   { int m_i = 0; while (flagcode_isValid (excludeCodes[m_i])) \
76       { flagcode m_c = excludeCodes[m_i]; m_i++; 
77
78 # define end_excludeFlagCodes }}
79
80 static bool matchPrefixChar (int nc, int pc)
81 {
82   if (nc == pc)
83     {
84       return TRUE;
85     }
86   else
87     {
88       switch (pc)
89         {
90         case PFX_UPPERCASE: 
91           return isupper (nc);
92         case PFX_LOWERCASE:
93           return islower (nc);
94         case PFX_ANY:
95           return TRUE;
96         case PFX_DIGIT:
97           return isdigit (nc);
98         case PFX_NOTUPPER:
99           return !isupper (nc);
100         case PFX_NOTLOWER:
101           return !islower (nc);
102         case PFX_ANYLETTER:
103           return isalpha (nc);
104         case PFX_ANYLETTERDIGIT: 
105           return (isdigit (nc) || isalpha (nc));
106         default: return FALSE;
107         }
108     }
109
110   BADEXIT;
111 }
112
113 static bool matchPrefix (cstring name, cstring prefix)
114 {
115   if (cstring_isUndefined (name)
116       || cstring_isUndefined (prefix))
117     {
118       return TRUE;
119     }
120   else
121     {
122       size_t namelen = cstring_length (name);
123       int last = (int) '\0';
124       size_t n = 1;
125
126       cstring_chars (prefix, pc)
127         {
128           int nc;
129
130           if (pc == '*')
131             {
132               n++;
133
134               while (n <= namelen)
135                 {
136                   nc = (int) cstring_getChar (name, n);
137
138                   if (!matchPrefixChar (nc, last))
139                     {
140                       return FALSE;
141                     }
142
143                   n++;
144                 }
145
146               return TRUE;
147             }
148           else
149             {
150               if (n > namelen)
151                 {
152                   if (namelen > 1
153                       && (cstring_length (prefix) >= n + 1)
154                       && cstring_getChar (prefix, n + 1) == '*')
155                     {
156                       return TRUE;
157                     }
158                   else
159                     {
160                       return FALSE;
161                     }
162                 }
163               
164               nc = (int) cstring_getChar (name, n);
165               
166               if (!matchPrefixChar (nc, (int) pc))
167                 {
168                   return FALSE;
169                 }
170             }
171         
172           last = (int) pc;
173           n++;
174         } end_cstring_chars;
175
176       return TRUE;
177     }
178 }
179
180 static flagcode
181 namespaceExcluded (flagcode code) /*@*/ 
182 {
183   switch (code)
184     {
185     case FLG_MACROVARPREFIXEXCLUDE:
186       return (FLG_MACROVARPREFIX);
187     case FLG_TAGPREFIXEXCLUDE:
188       return (FLG_TAGPREFIX);
189     case FLG_ENUMPREFIXEXCLUDE:
190       return (FLG_ENUMPREFIX);
191     case FLG_FILESTATICPREFIXEXCLUDE:
192       return (FLG_FILESTATICPREFIX);
193     case FLG_GLOBPREFIXEXCLUDE:
194       return (FLG_GLOBPREFIX);
195     case FLG_TYPEPREFIXEXCLUDE:
196       return (FLG_TYPEPREFIX);
197     case FLG_EXTERNALPREFIXEXCLUDE:
198       return (FLG_EXTERNALPREFIX);
199     case FLG_UNCHECKEDMACROPREFIXEXCLUDE:
200       return (FLG_UNCHECKEDMACROPREFIX);
201     case FLG_LOCALPREFIXEXCLUDE:
202       return (FLG_LOCALPREFIX);
203     case FLG_ITERPREFIXEXCLUDE:
204       return (FLG_ITERPREFIX);
205     case FLG_CONSTPREFIXEXCLUDE:
206       return (FLG_CONSTPREFIX);
207     BADDEFAULT;
208     }
209 }
210
211 static /*@observer@*/ cstring
212 namespaceName (flagcode flag) /*@*/
213 {
214   switch (flag)
215     {
216     case FLG_MACROVARPREFIX: 
217       return cstring_makeLiteralTemp ("macro variable");
218     case FLG_TAGPREFIX:  
219       return cstring_makeLiteralTemp ("tag");
220     case FLG_ENUMPREFIX:  
221       return cstring_makeLiteralTemp ("enum member");
222     case FLG_TYPEPREFIX:     
223       return cstring_makeLiteralTemp ("user-defined type");
224     case FLG_FILESTATICPREFIX:
225       return cstring_makeLiteralTemp ("file static");
226     case FLG_GLOBPREFIX: 
227       return cstring_makeLiteralTemp ("global variable");
228     case FLG_EXTERNALPREFIX: 
229       return cstring_makeLiteralTemp ("external");
230     case FLG_LOCALPREFIX: 
231       return cstring_makeLiteralTemp ("local variable");
232     case FLG_CONSTPREFIX: 
233       return cstring_makeLiteralTemp ("constant");
234     case FLG_ITERPREFIX: 
235       return cstring_makeLiteralTemp ("iter");
236     case FLG_UNCHECKEDMACROPREFIX: 
237       return cstring_makeLiteralTemp ("unchecked macro");
238     BADDEFAULT;
239     }
240 }
241
242 void
243 checkPrefix (uentry ue)
244 {
245   cstring name = cstring_undefined;
246   flagcode flag;
247
248   if (uentry_isExpandedMacro (ue))
249     {
250       flag = FLG_UNCHECKEDMACROPREFIX;
251     }
252   else if (uentry_isAnyTag (ue))
253     {
254       flag = FLG_TAGPREFIX;
255     }
256   else if (uentry_isEnumConstant (ue))
257     {
258       flag = FLG_ENUMPREFIX;
259     }
260   else if (uentry_isDatatype (ue))
261     {
262       flag = FLG_TYPEPREFIX;
263     }
264   else if (uentry_isFileStatic (ue))
265     {
266       flag = FLG_FILESTATICPREFIX;
267     }
268   else if (uentry_isGlobalVariable (ue))
269     {
270       flag = FLG_GLOBPREFIX;
271     }
272   else if (uentry_isVariable (ue))
273     {
274       if (uentry_isRefParam (ue))
275         {
276           return; /* already checked param */
277         }
278
279       if (context_inMacro ())
280         {
281           if (uentry_isAnyParam (ue))
282             {
283               if (uentry_isYield (ue))
284                 {
285                   flag = FLG_MACROVARPREFIX;
286                 }
287               else
288                 {
289                   flag = FLG_LOCALPREFIX;
290                 }
291             }
292           else
293             {
294               flag = FLG_MACROVARPREFIX;
295             }
296         }
297       else
298         {
299           flag = FLG_LOCALPREFIX;
300         }
301     }
302   else if (uentry_isConstant (ue))
303     {
304       flag = FLG_CONSTPREFIX;
305     }
306   else if (uentry_isIter (ue))
307     {
308       flag = FLG_ITERPREFIX;
309     }
310   else if (uentry_isExported (ue))
311     {
312       flag = FLG_EXTERNALPREFIX;
313     }
314   else
315     {
316       llcontbug (message ("What is it: %q", uentry_unparseFull (ue)));
317       return;
318     }
319
320   if (flag == FLG_TYPEPREFIX || flag == FLG_GLOBPREFIX
321       || flag == FLG_ENUMPREFIX || flag == FLG_CONSTPREFIX)
322     {
323       if (flag == FLG_ENUMPREFIX)
324         {
325           if (!context_getFlag (flag))
326             {
327               flag = FLG_CONSTPREFIX;
328             }
329         }
330
331       if (!context_getFlag (flag))
332         {
333           flag = FLG_EXTERNALPREFIX;
334         }
335     }
336
337   if (context_getFlag (flag))
338     {
339       name = uentry_observeRealName (ue);
340       
341       if (!matchPrefix (name, context_getString (flag)))
342         {
343           llassert (flag != FLG_NAMECHECKS);
344
345           if (optgenerror2
346               (flag, FLG_NAMECHECKS,
347                message ("%s %s name is not consistent with %s "
348                         "namespace prefix \"%s\"",
349                         uentry_ekindName (ue),
350                         name,
351                         namespaceName (flag),
352                         context_getString (flag)),
353                uentry_whereLast (ue)))
354             {
355               uentry_setHasNameError (ue);
356             }
357         }
358     }  
359
360   excludeFlagCodes (code)
361     {
362       bool check = FALSE;
363
364       if (context_getFlag (code))
365         {
366           /*@-loopswitchbreak@*/
367           switch (code)
368             {
369             case FLG_MACROVARPREFIXEXCLUDE:
370               check = (flag != FLG_MACROVARPREFIX);
371               break;
372             case FLG_TAGPREFIXEXCLUDE:
373               check = (flag != FLG_TAGPREFIX);
374               break;
375             case FLG_ENUMPREFIXEXCLUDE:
376               check = (flag != FLG_ENUMPREFIX);
377               break;
378             case FLG_FILESTATICPREFIXEXCLUDE:
379               check = (flag != FLG_FILESTATICPREFIX);
380               break;
381             case FLG_GLOBPREFIXEXCLUDE:
382               check = (flag != FLG_GLOBPREFIX);
383               break;
384             case FLG_TYPEPREFIXEXCLUDE:
385               check = (flag != FLG_TYPEPREFIX);
386               break;
387             case FLG_EXTERNALPREFIXEXCLUDE:
388               check = (flag != FLG_EXTERNALPREFIX
389                        && flag != FLG_GLOBPREFIX
390                        && flag != FLG_TYPEPREFIX
391                        && flag != FLG_UNCHECKEDMACROPREFIX);
392               break;
393             case FLG_UNCHECKEDMACROPREFIXEXCLUDE:
394               check = (flag != FLG_UNCHECKEDMACROPREFIX);
395               break;
396             case FLG_LOCALPREFIXEXCLUDE:
397               check = (flag != FLG_LOCALPREFIX);
398               break;
399             case FLG_CONSTPREFIXEXCLUDE:
400               check = (flag != FLG_CONSTPREFIX);
401               break;
402             case FLG_ITERPREFIXEXCLUDE:
403               check = (flag != FLG_ITERPREFIX);
404               break;
405             BADDEFAULT;
406             }
407           /*@=loopswitchbreak@*/
408
409           if (check)
410             {
411               flagcode rcode = namespaceExcluded (code);
412               cstring pstring = context_getString (rcode);
413
414               if (cstring_isDefined (pstring))
415                 {
416                   if (cstring_isUndefined (name))
417                     {
418                       name = uentry_observeRealName (ue);
419                     }
420                   
421                   if (matchPrefix (name, context_getString (rcode)))
422                     {
423                       if (optgenerror2
424                           (code, FLG_NAMECHECKS,
425                            message
426                            ("%s %s name is not a %s (it is a %s), "
427                             "but matches the %s "
428                             "namespace prefix \"%s\"",
429                             uentry_ekindName (ue),
430                             name,
431                             namespaceName (rcode),
432                             namespaceName (flag),
433                             namespaceName (rcode),
434                             context_getString (rcode)),
435                            uentry_whereLast (ue)))
436                         {
437                           uentry_setHasNameError (ue);
438                         }
439                     }
440                 }
441             }
442         } 
443     } end_excludeFlagCodes ;
444 }
445
446 static void
447 checkNationalName (uentry ue)
448 {
449   flagcode czechflag;
450   flagcode slovakflag;
451   flagcode czechoslovakflag;
452   bool gcf, gsf, gcsf;
453
454   
455   if (uentry_isFunction (ue)
456       || uentry_isIter (ue)
457       || uentry_isEndIter (ue))
458     {
459       czechflag = FLG_CZECHFUNCTIONS;
460       slovakflag = FLG_SLOVAKFUNCTIONS;
461       czechoslovakflag = FLG_CZECHOSLOVAKFUNCTIONS;
462     }
463   else if (uentry_isExpandedMacro (ue))
464     {
465       czechflag = FLG_CZECHMACROS;
466       slovakflag = FLG_SLOVAKMACROS;
467       czechoslovakflag = FLG_CZECHOSLOVAKMACROS;
468     }
469   else if (uentry_isVariable (ue))
470     {
471       if (uentry_isGlobalVariable (ue) && context_getFlag (FLG_GLOBPREFIX))
472         {
473           /* prefix checks supercede national naming checks */
474           return;
475         }
476
477       czechflag = FLG_CZECHVARS;
478       slovakflag = FLG_SLOVAKVARS;
479       czechoslovakflag = FLG_CZECHOSLOVAKVARS;
480     }
481   else if (uentry_isConstant (ue))
482     {
483       if (uentry_isGlobalVariable (ue) && context_getFlag (FLG_CONSTPREFIX))
484         {
485           /* prefix checks supercede national naming checks */
486           return;
487         }
488
489       czechflag = FLG_CZECHCONSTANTS;
490       slovakflag = FLG_SLOVAKCONSTANTS;
491       czechoslovakflag = FLG_CZECHOSLOVAKCONSTANTS;
492     }
493   else
494     {
495       if (uentry_isAnyTag (ue) || uentry_isEnumConstant (ue))
496         {
497           return; /* no errors for tags */
498         }
499       
500       llassert (uentry_isDatatype (ue));
501
502       czechflag = FLG_CZECHTYPES;
503       slovakflag = FLG_SLOVAKTYPES;
504       czechoslovakflag = FLG_CZECHOSLOVAKTYPES;
505     }
506
507   gcf = context_getFlag (czechflag);
508   gsf = context_getFlag (slovakflag);
509   gcsf = context_getFlag (czechoslovakflag);
510
511   if (gcf || (uentry_isFunction (ue) 
512               && context_getFlag (FLG_ACCESSCZECH)))
513     {
514             (void) checkCzechName (ue, czechflag, gcf);
515     }
516
517   if (gsf || (uentry_isFunction (ue) 
518               && context_getFlag (FLG_ACCESSSLOVAK)))
519     {
520       (void) checkSlovakName (ue, slovakflag, gsf);
521     }
522
523   if (gcsf)
524     {
525       if (uentry_isDatatype (ue))
526         {
527           /* May not have either _'s or uppercase letter */
528           cstring name = uentry_rawName (ue);
529           int charno = 1;
530
531           cstring_chars (name, c)
532             {
533               if (isupper ((unsigned char) c))
534                 {
535                   if (optgenerror2
536                       (FLG_CZECHOSLOVAKTYPES, FLG_NAMECHECKS,
537                        message
538                        ("%s %q name violates Czechoslovak naming convention.  "
539                         "Czechoslovak datatype names should not use uppercase "
540                         "letters.",
541                         uentry_ekindName (ue),
542                         uentry_getName (ue)),
543                        uentry_whereLast (ue)))
544                     {
545                       uentry_setHasNameError (ue);
546                     }
547                   break;
548                 }
549
550               if (c == '_' && charno != 2 && charno != 3)
551                 {
552                   if (optgenerror2
553                       (FLG_CZECHOSLOVAKTYPES, FLG_NAMECHECKS,
554                        message ("%s %q name violates Czechoslovak naming "
555                                 "convention.  Czechoslovak datatype names "
556                                 "should not use the _ charater.",
557                                 uentry_ekindName (ue),
558                                 uentry_getName (ue)),
559                        uentry_whereLast (ue)))
560                     {
561                       uentry_setHasNameError (ue);
562                     }
563                   break;
564                 }
565               
566               charno++;
567             } end_cstring_chars;
568         }
569       else
570         {
571           bool okay = checkCzechName (ue, czechflag, FALSE);
572           
573           /* still need to call, to set access */
574           okay |= checkSlovakName (ue, slovakflag, FALSE);
575           
576           if (!okay)
577             {
578               if (optgenerror2
579                   (czechoslovakflag, FLG_NAMECHECKS,
580                    message ("%s %q name is not consistent with Czechoslovak "
581                             "naming convention.",
582                             uentry_ekindName (ue),
583                             uentry_getName (ue)),
584                    uentry_whereLast (ue)))
585                 {
586                   uentry_setHasNameError (ue);
587                 }
588             }
589         }
590     }
591 }
592
593 static bool checkCzechName (uentry ue, flagcode czechflag, bool report)
594 {
595   if (uentry_isDatatype (ue))
596     {
597       /*
598       ** Czech datatypes may not have _'s, except if there are 1 or 2 characters
599       ** before the only _.
600       */
601
602       cstring name = uentry_rawName (ue);
603       int charno = 1;
604       
605       cstring_chars (name, c)
606         {
607           if (c == '_' && charno != 2 && charno != 3)
608             {
609               if (report)
610                 {
611                   if (optgenerror2
612                       (FLG_CZECHTYPES, FLG_NAMECHECKS,
613                        message 
614                        ("%s %q name violates Czech naming convention.  "
615                         "Czech datatype names should not use the _ charater.",
616                         uentry_ekindName (ue),
617                         uentry_getName (ue)),
618                        uentry_whereLast (ue)))
619                     {
620                       uentry_setHasNameError (ue);
621                     }
622                 }
623
624               return FALSE;
625             }
626           
627           charno++;
628         } end_cstring_chars;
629     }
630   else
631     {
632       typeIdSet acc = context_fileAccessTypes ();
633       cstring pfx = czechPrefix (uentry_rawName (ue));
634
635       if (cstring_isEmpty (pfx))
636         {
637           if (uentry_isVariable (ue) || uentry_isConstant (ue))
638             {
639               ctype ct = uentry_getType (ue);
640               
641               if (ctype_isAbstract (ct)
642                   && context_hasAccess (ctype_typeId (ct)))
643                 {
644                   if (report)
645                     {
646                       if (optgenerror2
647                           (czechflag, FLG_NAMECHECKS,
648                            message ("%s %q name is not consistent with Czech "
649                                     "naming convention.  The name should "
650                                     "begin with %s_",
651                                     uentry_ekindName (ue),
652                                     uentry_getName (ue),
653                                     ctype_unparse (ct)),
654                            uentry_whereLast (ue)))
655                         {
656                           uentry_setHasNameError (ue);
657                         }
658                     }
659
660                   cstring_free (pfx);
661                   return FALSE;
662                 }
663             }
664           else if (uentry_isFunction (ue) || uentry_isIter (ue))
665             {
666               if (typeIdSet_isEmpty (acc))
667                 {
668                   ; /* okay - should not be czech name */
669                 }
670               else
671                 {
672                   if (report)
673                     {
674                       if (optgenerror2
675                           (czechflag, FLG_NAMECHECKS,
676                            message ("%s %q name is not consistent with Czech "
677                                     "naming convention.  Accessible types: %q",
678                                     uentry_ekindName (ue),
679                                     uentry_getName (ue),
680                                     typeIdSet_unparse (acc)),
681                            uentry_whereLast (ue)))
682                         {
683                           uentry_setHasNameError (ue);
684                         }
685                     }
686
687                   cstring_free (pfx);
688                   return FALSE;
689                 }
690             }
691           else
692             {
693               ;
694             }
695         }
696       else
697         {
698           if (usymtab_existsTypeEither (pfx))
699             {
700               ctype ct = usymtab_lookupAbstractType (pfx);
701               typeId tid;
702               
703               if (ctype_isUA (ct))
704                 {
705                   tid = ctype_typeId (ct);
706                   
707                   if (ctype_isUser (ct) || context_hasAccess (tid))
708                     {
709                       ;
710                     }
711                   else
712                     {
713                       if (context_getFlag (FLG_ACCESSCZECH)
714                           || context_getFlag (FLG_ACCESSCZECHOSLOVAK))
715                         {
716                           if (!uentry_isVar (ue))
717                             {
718                               uentry_addAccessType (ue, tid);
719                             }
720                         }
721                       else
722                         {
723                           if (report)
724                             {
725                               if (llgenhinterror
726                                   (czechflag,
727                                    message 
728                                    ("%s %q name violates Czech naming "
729                                     "convention. Czech prefix %s names "
730                                     "an abstract type that is "
731                                     "not accessible.",
732                                     uentry_ekindName (ue),
733                                     uentry_getName (ue),
734                                     pfx),
735                                    cstring_makeLiteral 
736                                    ("Use +accessczech to allow access to "
737                                     "type <t> in functions "
738                                     "named <t>_<name>."), 
739                                    uentry_whereLast (ue)))
740                                 {
741                                   uentry_setHasNameError (ue);
742                                 }
743                             }
744                           
745                           cstring_free (pfx);
746                           return FALSE;
747                         }
748                     }
749                 }
750               else if (ctype_isManifestBool (ct))
751                 {
752                   if (context_canAccessBool ())
753                     {
754                       ;
755                     }
756                   else
757                     {
758                       if (context_getFlag (FLG_ACCESSCZECH)
759                           || context_getFlag (FLG_ACCESSCZECHOSLOVAK))
760                         {
761                           if (!uentry_isVar (ue))
762                             {
763                               tid = usymtab_getTypeId (context_getBoolName ());
764                               uentry_addAccessType (ue, tid);
765                             }
766                         }
767                       else
768                         {
769                           if (report)
770                             {
771                               if (llgenhinterror
772                                   (czechflag,
773                                    message
774                                    ("%s %q name violates Czech naming "
775                                     "convention. Type bool is not accessible.",
776                                     uentry_ekindName (ue),
777                                     uentry_getName (ue)),
778                                    cstring_makeLiteral 
779                                    ("Use +accessczech to allow access to "
780                                     "type <t> in functions named <t>_<name>."), 
781                                    uentry_whereLast (ue)))
782                                 {
783                                   uentry_setHasNameError (ue);
784                                 }
785                             }
786                           
787                           cstring_free (pfx);
788                           return FALSE;
789                         }
790                     }
791                 }
792               else
793                 {
794                   ;
795                 }
796             }
797           else
798             {
799               if (cstring_equalLit (pfx, "int")
800                   || cstring_equalLit (pfx, "char")
801                   || cstring_equalLit (pfx, "short")
802                   || cstring_equalLit (pfx, "long")
803                   || cstring_equalLit (pfx, "unsigned")
804                   || cstring_equalLit (pfx, "signed")
805                   || cstring_equalLit (pfx, "float")
806                   || cstring_equalLit (pfx, "double"))
807                 {
808                   ; /* built-in types */
809                 }
810               else
811                 {
812                   /* no accessible types, could match module name */
813                   
814                   if (cstring_equal (pfx, context_moduleName ()))
815                     {
816                       ;
817                     }
818                   else
819                     {
820                       if (report)
821                         {
822                           if (optgenerror2
823                               (czechflag, FLG_NAMECHECKS,
824                                message 
825                                ("%s %q name violates Czech naming convention.  "
826                                 "Czech prefix %s is not the name of a type.",
827                                 uentry_ekindName (ue),
828                                 uentry_getName (ue),
829                                 pfx),
830                                uentry_whereLast (ue)))
831                             {
832                               uentry_setHasNameError (ue);
833                             }
834                         }
835
836                       cstring_free (pfx);                     
837                       return FALSE;
838                     }
839                 }
840             }
841         }
842       cstring_free (pfx);
843     }
844
845   return TRUE;
846 }
847
848 static bool checkSlovakName (uentry ue, flagcode slovakflag, bool report)
849 {
850   if (uentry_isDatatype (ue))
851     {
852       /*
853       ** Slovak datatypes may not have uppercase letters.
854       */
855
856       if (context_getFlag (FLG_SLOVAK))
857         {
858           cstring name = uentry_rawName (ue);
859
860           cstring_chars (name, c)
861             {
862               if (isupper ((unsigned char) c))
863                 {
864                   if (report)
865                     {
866                       if (optgenerror2
867                           (FLG_SLOVAKTYPES, FLG_NAMECHECKS,
868                            message 
869                            ("%s %q name violates Slovak naming convention.  "
870                             "Slovak datatype names should not use uppercase "
871                             "letters.",
872                             uentry_ekindName (ue),
873                             uentry_getName (ue)),
874                            uentry_whereLast (ue)))
875                         {
876                           uentry_setHasNameError (ue);
877                         }
878                     }
879                   return FALSE;
880                 }
881             } end_cstring_chars;
882         }
883     }
884   else
885     {
886       typeIdSet acc = context_fileAccessTypes ();
887       cstring pfx = slovakPrefix (uentry_rawName (ue));
888       
889       if (cstring_isEmpty (pfx))
890         {
891           if (typeIdSet_isEmpty (acc))
892             {
893               ; /* okay - should not be slovak name */
894             }
895           else
896             {
897               if (uentry_isFunction (ue))
898                 {
899                   if (report)
900                     {
901                       if (optgenerror2
902                           (slovakflag, FLG_NAMECHECKS,
903                            message ("%s %q name is not consistent with Slovak "
904                                     "naming convention.  Accessible types: %q",
905                                     uentry_ekindName (ue),
906                                     uentry_getName (ue),
907                                     typeIdSet_unparse (acc)),
908                            uentry_whereLast (ue)))
909                         {
910                           uentry_setHasNameError (ue);
911                         }
912                     }
913                   
914                   cstring_free (pfx);
915                   return FALSE;
916                 }
917               else
918                 {
919                   ctype ct = uentry_getType (ue);
920                   
921                   if (ctype_isUA (ct))
922                     {
923                       if (report)
924                         {
925                           if (optgenerror2
926                               (slovakflag, FLG_NAMECHECKS,
927                                message ("%s %q name is not consistent with "
928                                         "Slovak naming convention.  The "
929                                         "name should begin with %s followed "
930                                         "by an uppercase letter.",
931                                         uentry_ekindName (ue),
932                                         uentry_getName (ue),
933                                         ctype_unparse (ct)),
934                                uentry_whereLast (ue)))
935                             {
936                               uentry_setHasNameError (ue);
937                             }   
938                         }
939                       
940                       cstring_free (pfx);
941                       return FALSE;
942                     }
943                 }
944             }
945         }
946       else
947         {
948           if (usymtab_existsTypeEither (pfx))
949             {
950               ctype ct = usymtab_lookupAbstractType (pfx);
951               typeId tid;
952               
953               if (ctype_isUA (ct))
954                 {
955                   tid = ctype_typeId (ct);
956                   
957                   if (ctype_isUser (ct) || context_hasAccess (tid))
958                     {
959                       ;
960                     }
961                   else
962                     {
963                       if (context_getFlag (FLG_ACCESSSLOVAK)
964                           || context_getFlag (FLG_ACCESSCZECHOSLOVAK))
965                         {
966                           if (!uentry_isVar (ue))
967                             {
968                               uentry_addAccessType (ue, tid);
969                             }
970                         }
971                       else
972                         {
973                           if (report)
974                             {
975                               if (llgenhinterror
976                                   (slovakflag,
977                                    message 
978                                    ("%s %q name violates Slovak naming "
979                                     "convention. Slovak prefix %s names "
980                                     "an abstract type that is not accessible.",
981                                     uentry_ekindName (ue),
982                                     uentry_getName (ue),
983                                     pfx),
984                                    cstring_makeLiteral 
985                                    ("Use +accessslovak to allow access to "
986                                     "type <t> in functions named <t>_<name>."), 
987                                    uentry_whereLast (ue)))
988                                 {
989                                   uentry_setHasNameError (ue);
990                                 }
991                             }
992                           
993                           cstring_free (pfx);
994                           return FALSE;
995                         }
996                     }
997                 }
998               else if (ctype_isManifestBool (ct))
999                 {
1000                   if (context_canAccessBool ())
1001                     {
1002                       ;
1003                     }
1004                   else
1005                     {
1006                       if (context_getFlag (FLG_ACCESSSLOVAK)
1007                           || context_getFlag (FLG_ACCESSCZECHOSLOVAK))
1008                         {
1009                           if (!uentry_isVar (ue))
1010                             {
1011                               tid = usymtab_getTypeId (context_getBoolName ());
1012                               uentry_addAccessType (ue, tid);
1013                             }
1014                         }
1015                       else
1016                         {
1017                           if (report)
1018                             {
1019                               if (llgenhinterror
1020                                   (slovakflag,
1021                                    message
1022                                    ("%s %q name violates Slovak naming convention.  "
1023                                     "Type bool is not accessible.",
1024                                     uentry_ekindName (ue),
1025                                     uentry_getName (ue)),
1026                                    cstring_makeLiteral
1027                                    ("Use +accessslovak to allow access to "
1028                                     "type <t> in functions named <t>_<name>."),
1029                                    uentry_whereLast (ue)))
1030                                 {
1031                                   uentry_setHasNameError (ue);
1032                                 }
1033                             }
1034                           
1035                           cstring_free (pfx);
1036                           return FALSE;
1037                         }
1038                     }
1039                 }
1040               else
1041                 {
1042                   ;
1043                 }
1044             }
1045           else
1046             {
1047               if (cstring_equalLit (pfx, "int")
1048                   || cstring_equalLit (pfx, "char")
1049                   || cstring_equalLit (pfx, "short")
1050                   || cstring_equalLit (pfx, "long")
1051                   || cstring_equalLit (pfx, "unsigned")
1052                   || cstring_equalLit (pfx, "signed")
1053                   || cstring_equalLit (pfx, "float")
1054                   || cstring_equalLit (pfx, "double"))
1055                 {
1056                   ; /* built-in types */
1057                 }
1058               else
1059                 {
1060                   /* no accessible types, could match module name */
1061                   
1062                   if (cstring_equal (pfx, context_moduleName ()))
1063                     {
1064                       ;
1065                     }
1066                   else
1067                     {
1068                       if (report)
1069                         {
1070                           if (optgenerror2
1071                               (slovakflag, FLG_NAMECHECKS,
1072                                message 
1073                                ("%s %q name violates Slovak naming convention.  "
1074                                 "Slovak prefix %s is not the name of a type.",
1075                                 uentry_ekindName (ue),
1076                                 uentry_getName (ue),
1077                                 pfx),
1078                                uentry_whereLast (ue)))
1079                             {
1080                               uentry_setHasNameError (ue);
1081                             }
1082                         }
1083
1084                       cstring_free (pfx);
1085                       return FALSE;
1086                     }
1087                 }
1088             }
1089         }
1090
1091       cstring_free (pfx);
1092     }
1093
1094   return TRUE;
1095 }
1096
1097 void
1098 checkExternalName (uentry ue)
1099 {
1100   if (!uentry_isStatic (ue) && uentry_hasName (ue))
1101     {
1102       checkNationalName (ue);
1103     }
1104   else
1105     {
1106       ;
1107     }
1108 }
1109
1110 void
1111 checkLocalName (/*@unused@*/ uentry ue)
1112 {
1113   /*
1114   ** No local checks (yet)
1115   */
1116
1117   return;
1118 }
1119
1120 void
1121 checkFileScopeName (/*@unused@*/ uentry ue)
1122 {
1123   /*
1124   ** No file scope checks (yet)
1125   */
1126
1127   /* add a file scope naming convention policy? */
1128
1129   return;
1130 }
1131
1132 /*
1133 ** Checks a name used by user source is not reserved by ANSI 
1134 ** (or for future library functions).
1135 **
1136 ** The restrictions are described in X3.159-1989: 4.13
1137 */
1138
1139 /*@constant int NRESERVEDNAMES; @*/
1140 # define NRESERVEDNAMES 201
1141
1142 /*@constant int NCPPNAMES@*/
1143 # define NCPPNAMES 39
1144
1145 void
1146 checkCppName (uentry ue)
1147 {
1148   cstring name = uentry_observeRealName (ue);
1149
1150   static ob_mstring cppNames[NCPPNAMES] =
1151     {
1152       "and", "and_eq", "asm", 
1153       "bitand", "bitor", "bool", /* gasp: "bool", is special for splint */
1154       "catch", "class", "compl", "const_class",
1155       "delete", "dynamic_cast", "false", "friend",
1156       "inline", "mutable", "namespace", "new",
1157       "not", "not_eq",
1158       "operator", "or", "or_eq", "overload",
1159       "private", "protected", "public",
1160       "reinterpret_cast", "static_cast",
1161       "template", "this", "throw", "true", "try",
1162       "typeid", "using", "virtual", "xor", "xor_eq"
1163       } ;
1164   
1165   if (cstring_isDefined (cstring_bsearch (name, &cppNames[0],
1166                                           NCPPNAMES)))
1167     {
1168       if (optgenerror2
1169           (FLG_CPPNAMES, FLG_NAMECHECKS,
1170            message ("Name %s is a keyword or reserved word in C++",
1171                     name),
1172            uentry_whereLast (ue)))
1173         {
1174           uentry_setHasNameError (ue);
1175         }
1176     }
1177 }
1178
1179 void
1180 checkAnsiName (uentry ue)
1181 {
1182   bool hasError = FALSE;
1183   cstring name = uentry_observeRealName (ue);
1184   size_t length = cstring_length (name);
1185   char fchar = (length >= 1) ? cstring_firstChar (name) : '\0';
1186   char schar = (length >= 2) ? cstring_secondChar (name) : '\0';
1187   char tchar = (length >= 3) ? cstring_getChar (name, 3) : '\0';
1188   char rchar = (length >= 4) ? cstring_getChar (name, 4) : '\0';
1189
1190   /* 
1191   ** reservedNames
1192   **   taken from Linden, "Expert C Programming", p. 126-8. 
1193   **   invariant:  must be sorted (case-insensitive, lexicographically)
1194   **               must end with NULL
1195   */
1196
1197   static ob_mstring reservedNames[NRESERVEDNAMES] =
1198     { 
1199 # include "reservedNames.nf"
1200     } ;
1201
1202 # if 0
1203   /*
1204   ** This code is for checking reservedNames.nf
1205   */
1206
1207   {
1208     int i = 0;
1209     char *lastname = NULL;
1210     char *name;
1211     
1212     while ((name = reservedNames[i]) != NULL)
1213       {
1214         llassertprint (lastname == NULL
1215                        || strcmp (name, lastname) > 0,
1216                        ("%s / %s", lastname, name));
1217         lastname = name;
1218         i++;
1219       }
1220     
1221     nreservedNames = i - 1;
1222   }
1223 # endif
1224
1225   if (fileloc_isSystemFile (uentry_whereLast (ue)) || fileloc_isBuiltin (uentry_whereLast (ue)))
1226     {
1227       return;  /* no errors for system files */
1228     }
1229   
1230   if (cstring_isDefined (cstring_bsearch (name, &reservedNames[0],
1231                                           NRESERVEDNAMES)))
1232     {
1233       hasError |= optgenerror2
1234         (FLG_ISORESERVED, FLG_NAMECHECKS,
1235          message ("Name %s is reserved for the standard library",
1236                   name),
1237          uentry_whereLast (ue));
1238     }
1239
1240   if (uentry_isFileStatic (ue) || uentry_isVisibleExternally (ue) || uentry_isAnyTag (ue)
1241       || context_getFlag (FLG_ISORESERVEDLOCAL))
1242     {
1243       if (fchar == '_')
1244         {
1245           hasError |= optgenerror2
1246             (FLG_ISORESERVED, FLG_NAMECHECKS,
1247              message 
1248              ("Name %s is in the implementation name space (any identifier "
1249               "beginning with underscore)", 
1250               name),
1251              uentry_whereLast (ue));
1252         }
1253     }
1254   else
1255     {
1256       /*
1257       ** ISO 7.1.3:
1258       ** - All identifiers that begin with an underscore and either an uppercase
1259       ** letter or another underscore are always reserved for any use.
1260       */
1261       
1262       if (fchar == '_' 
1263           && (schar == '_' || isupper ((int) schar)))
1264         {
1265           hasError |= optgenerror2
1266             (FLG_ISORESERVED, FLG_NAMECHECKS,
1267              message 
1268              ("Name %s is in the implementation name space (any identifier "
1269               "beginning with underscore and either an uppercase letter or "
1270               "another underscore is always reserved for any use)", 
1271               name),
1272              uentry_whereLast (ue));
1273         }
1274     }
1275
1276   /*
1277   ** 4.13.1 Errors <errno.h>
1278   **
1279   ** Macros that begin with E and a digit or E and an uppercase letter ...
1280   */
1281   
1282   if (fchar == 'E' && (isdigit ((int) schar) 
1283                        || isupper ((int) schar)))
1284     {
1285       hasError |= optgenerror2
1286         (FLG_ISORESERVED, FLG_NAMECHECKS,
1287          message 
1288          ("Name %s is reserved for future library extensions. "
1289           "Macros beginning with E and a digit or uppercase letter "
1290           "may be added to <errno.h>. (ISO99:7.26.3)",
1291           name),
1292          uentry_whereLast (ue));
1293     }
1294
1295   /*
1296   ** 4.13.3 Localization <locale.h>
1297   **
1298   ** Macros that begin with LC_ and an uppercase letter ...
1299   */
1300   
1301   if (length >= 4 
1302       && ((fchar == 'L')
1303           && (schar == 'C')
1304           && (tchar == '_'))
1305       && (isupper ((int) rchar)))
1306     {
1307       hasError |= optgenerror2
1308         (FLG_ISORESERVED, FLG_NAMECHECKS,
1309          message
1310          ("Name %s is reserved for future library extensions.  "
1311           "Macros beginning with \"LC_\" and an uppercase letter may "
1312           "be added to <locale.h>. (ISO99:7.26.5)",
1313           name),
1314          uentry_whereLast (ue));
1315     }
1316
1317   /*
1318   ** 4.13.5 Signal Handling <signal.h>
1319   **
1320   ** Macros that begin with either SIG or SIG_ and an uppercase letter or...
1321   */
1322   
1323   if (fchar == 'S' && schar == 'I' && tchar == 'G'
1324            && ((rchar == '_' && ((length >= 5 
1325                                   && isupper ((int) cstring_getChar (name, 5)))))
1326                || (isupper ((int) rchar))))
1327     {
1328       hasError |= optgenerror2
1329         (FLG_ISORESERVED, FLG_NAMECHECKS,
1330          message
1331          ("Name %s is reserved for future library extensions.  "
1332           "Macros that begin with SIG and an uppercase letter or SIG_ "
1333           "and an uppercase letter may be added to "
1334           "<signal.h>. (ISO99:7.14)",
1335           name),
1336          uentry_whereLast (ue));
1337     }
1338
1339   /*
1340   ** evans - 2002-12-16: added this check (even though it is not required by ISO)
1341   */
1342
1343   if (fchar == 'S' && schar == 'A' && tchar == '_')
1344     {
1345       hasError |= optgenerror2
1346         (FLG_ISORESERVED, FLG_NAMECHECKS,
1347          message 
1348          ("Name %s may be defined as a macro by Linux library. "
1349           "It is not research by the ISO specification, but may produce conflicts on some systems.",
1350           name),
1351          uentry_whereLast (ue));
1352     }
1353
1354   if ((uentry_isVisibleExternally (ue) && !uentry_isAnyTag (ue))
1355       || context_getFlag (FLG_ISORESERVEDLOCAL))
1356     {
1357       flagcode flg;
1358
1359       DPRINTF (("Okay...: %s", uentry_unparse (ue)));
1360
1361       if (uentry_isVisibleExternally (ue) && !uentry_isAnyTag (ue))
1362         {
1363           flg = FLG_ISORESERVED;
1364         }
1365       else
1366         {
1367           flg = FLG_ISORESERVEDLOCAL;
1368         }
1369
1370       DPRINTF (("ue: %s", uentry_unparseFull (ue)));
1371
1372       /*
1373       ** These restrictions only apply to identifiers with global linkage.
1374       */
1375
1376       /*
1377       ** 4.13.2 Character Handling <ctype.h>
1378       **
1379       ** Function names that begin with either "is" or "to" and a lowercase letter ...
1380       */
1381       
1382       if (((fchar == 'i' && schar == 's') 
1383            || (fchar == 't' && schar == 'o'))
1384           && (islower ((int) tchar)))
1385         {
1386           hasError |= optgenerror2
1387             (flg, FLG_NAMECHECKS,
1388              message
1389              ("Name %s is reserved for future library extensions.  "
1390               "Functions beginning with \"is\" or \"to\" and a lowercase "
1391               "letter may be added to <ctype.h>. (ISO99:7.26.2)",
1392               name),
1393              uentry_whereLast (ue));
1394
1395           DPRINTF (("Externally visible: %s / %s",
1396                     uentry_unparseFull (ue),
1397                     bool_unparse (uentry_isVisibleExternally (ue))));
1398         }
1399       
1400       
1401       /*
1402       ** 4.13.4 Mathematics <math.h>
1403       **
1404       ** The names of all existing functions declared in the <math.h> header, 
1405       ** suffixed with f or l...
1406       */
1407
1408       DPRINTF (("Check name: %s", name));
1409
1410       if ((cstring_lastChar (name) == 'f' || cstring_lastChar (name) == 'l')
1411           && 
1412           (((length == 4)
1413             && ((cstring_equalPrefixLit (name, "cos") ||
1414                  cstring_equalPrefixLit (name, "sin") ||
1415                  cstring_equalPrefixLit (name, "tan") ||
1416                  cstring_equalPrefixLit (name, "exp") ||
1417                  cstring_equalPrefixLit (name, "log") ||
1418                  cstring_equalPrefixLit (name, "pow"))))
1419            || ((length == 5)
1420                && ((cstring_equalPrefixLit (name, "acos") ||
1421                     cstring_equalPrefixLit (name, "asin") ||
1422                     cstring_equalPrefixLit (name, "atan") ||
1423                     cstring_equalPrefixLit (name, "cosh") ||
1424                     cstring_equalPrefixLit (name, "sinh") ||
1425                     cstring_equalPrefixLit (name, "sqrt") ||
1426                     cstring_equalPrefixLit (name, "ceil") ||
1427                     cstring_equalPrefixLit (name, "fabs") ||
1428                     cstring_equalPrefixLit (name, "fmod") ||
1429                     cstring_equalPrefixLit (name, "tanh") ||
1430                     cstring_equalPrefixLit (name, "modf"))))
1431            || ((length == 6)
1432                && ((cstring_equalPrefixLit (name, "atan2") ||
1433                     cstring_equalPrefixLit (name, "floor") ||
1434                     cstring_equalPrefixLit (name, "frexp") ||
1435                     cstring_equalPrefixLit (name, "ldexp") ||
1436                     cstring_equalPrefixLit (name, "log10"))))))
1437         {
1438           hasError |= optgenerror2
1439             (flg, FLG_NAMECHECKS,
1440              message
1441              ("Name %s is reserved for future library extensions.  "
1442               "The names of all existing functions in <math.h> suffixed "
1443               "with 'f' or 'l' may be added to <math.h>. (ISO:7.26.1)",
1444               name),
1445              uentry_whereLast (ue));
1446         }
1447       
1448       /*
1449       ** 4.13.6 Input/Output <stdio.h>
1450       **
1451       ** (nothing to check)
1452       */
1453       
1454       /*
1455       ** 4.13.7 General Utilities <stdlib.h>
1456       **
1457       ** Functions names that begin with str and a lowercase letter may be added to <stdlib.h>.
1458       */
1459       
1460       if (fchar == 's' && schar == 't' && tchar == 'r' 
1461           && (islower ((int) rchar)))
1462         {
1463           hasError |= optgenerror2
1464             (flg, FLG_NAMECHECKS,
1465              message
1466              ("Name %s is reserved for future library extensions.  "
1467               "Functions that begin with \"str\" and a lowercase letter "
1468               "may be added to <stdlib.h> or <string.h>. (ISO99:7.26.9)",
1469               name),
1470              uentry_whereLast (ue));
1471         }
1472       
1473       /*
1474       ** 4.13.8 String Handling <string.h>
1475       **
1476       ** Function names that begin with str, mem, or wcs and a lowercase letter ...
1477       **
1478       ** (Note: already checked "str" above.)
1479       */
1480       
1481       if (((fchar == 'm' && schar == 'e' && tchar == 'm')
1482            || (fchar == 'w' && schar == 'c' && tchar == 's'))
1483           && (islower ((int) rchar)))
1484         {
1485           hasError |= optgenerror2
1486             (flg, FLG_NAMECHECKS,
1487              message
1488              ("Name %s is reserved for future library extensions.  "
1489               "Functions that begin with \"mem\" or \"wcs\" and a "
1490               "lowercase letter letter may be added to <string.h>. (ISO:7.26.11)",
1491               name),
1492              uentry_whereLast (ue));
1493         }
1494     }
1495   else
1496     {
1497       DPRINTF (("Not checked: [%s] %s", bool_unparse (uentry_isVisibleExternally (ue)),
1498                 uentry_unparseFull (ue)));
1499     }
1500
1501   if (hasError)
1502     {
1503       uentry_setHasNameError (ue);
1504     }
1505 }
1506
1507 void checkParamNames (uentry ue)
1508 {
1509   cstring fpfx = context_getString (FLG_DECLPARAMPREFIX);
1510   bool noformal = context_getFlag (FLG_DECLPARAMNAME);
1511
1512   llassert (uentry_isFunction (ue));
1513   
1514   if (cstring_isDefined (fpfx) || noformal)
1515     {
1516       uentryList params = uentry_getParams (ue);
1517       
1518       uentryList_elements (params, p)
1519         {
1520           if (uentry_hasName (p))
1521             {
1522               if (noformal && !cstring_isDefined (fpfx))
1523                 {
1524                   if (optgenerror2
1525                       (FLG_DECLPARAMNAME, FLG_NAMECHECKS,
1526                        message ("Declaration parameter has name: %q",
1527                                 uentry_getName (p)),
1528                        uentry_whereLast (p)))
1529                     {
1530                       uentry_setHasNameError (p);
1531                     }
1532                 }
1533               else
1534                 {
1535                   cstring pname = uentry_observeRealName (p);
1536                   
1537                   if (!cstring_equalPrefix (pname, fpfx))
1538                     {
1539                       if (context_getFlag (FLG_NAMECHECKS))
1540                         {
1541                           if (optgenerror2
1542                               (FLG_DECLPARAMPREFIX, FLG_NAMECHECKS,
1543                                message ("Declaration parameter name %s does not begin "
1544                                         "with protoparamprefix (%s)",
1545                                         pname, fpfx),
1546                                uentry_whereLast (p)))
1547                             {
1548                               uentry_setHasNameError (p);
1549                             }
1550                         }
1551                     }
1552                 }
1553             }
1554         } end_uentryList_elements ;
1555     }
1556 }
1557
1558 /* not yet checked: POSIX p. 527 - applications should not declare any symbols that end _MAX */
This page took 0.166005 seconds and 3 git commands to generate.